Overview

Preperation of the capelin (Mallotus villosus) data obtained from OBIS. This database shows the global occurance of capelin.

A note to anyone who might happen to stumble across this… I am a beginner in R and have had no exposure to similar languages. The code herein is unlikely to be elegant and there is likely more efficient ways of running the code.

Built with ‘r getRversion()’.

Package dependencies

You can load them using the following code which uses a function called ipak. Note this function checks to see if the packages are installed first. Th

packages <- c("rworldmap", "plyr")
source("../src/ipak.R")
ipak(packages)
rworldmap      plyr 
     TRUE      TRUE 
suppressMessages(ipak)
function(pkg){
  new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
  if (length(new.pkg)) 
    install.packages(new.pkg, dependencies = TRUE)
  sapply(pkg, require, character.only = TRUE)
}

Raw Data Clean

Load the raw data, then check use head() to check it looks ok, then names() to see all the column names

rawdata <- read.csv("../data/bio/capelin_obis_raw.csv")
head(rawdata) 
names(rawdata)
  [1] "id"                               "valid_id"                        
  [3] "resource_id"                      "position_id"                     
  [5] "latitude"                         "longitude"                       
  [7] "datecollected"                    "depth"                           
  [9] "qc"                               "institutioncode"                 
 [11] "collectioncode"                   "catalognumber"                   
 [13] "yearcollected"                    "individualcount"                 
 [15] "resname"                          "tname"                           
 [17] "tauthor"                          "worms_id"                        
 [19] "scientificnameid"                 "storedpath"                      
 [21] "originalscientificname"           "geom"                            
 [23] "phylum"                           "class"                           
 [25] "order"                            "family"                          
 [27] "genus"                            "species"                         
 [29] "phylum_id"                        "class_id"                        
 [31] "order_id"                         "family_id"                       
 [33] "genus_id"                         "species_id"                      
 [35] "group_id"                         "node_id"                         
 [37] "id.1"                             "acceptednameusage"               
 [39] "acceptednameusageid"              "accessrights"                    
 [41] "associatedmedia"                  "associatedoccurrences"           
 [43] "associatedreferences"             "associatedsequences"             
 [45] "associatedtaxa"                   "basisofrecord"                   
 [47] "bed"                              "behavior"                        
 [49] "bibliographiccitation"            "collectionid"                    
 [51] "continent"                        "coordinateprecision"             
 [53] "coordinateuncertaintyinmeters"    "countrycode"                     
 [55] "county"                           "datageneralizations"             
 [57] "datasetid"                        "dateidentified"                  
 [59] "disposition"                      "dynamicproperties"               
 [61] "establishmentmeans"               "eventdate"                       
 [63] "eventid"                          "eventremarks"                    
 [65] "eventtime"                        "fieldnotes"                      
 [67] "fieldnumber"                      "footprintspatialfit"             
 [69] "footprintsrs"                     "footprintwkt"                    
 [71] "geodeticdatum"                    "group"                           
 [73] "habitat"                          "higherclassification"            
 [75] "highergeography"                  "highergeographyid"               
 [77] "identificationid"                 "identificationqualifier"         
 [79] "identificationreferences"         "identificationremarks"           
 [81] "identificationverificationstatus" "identifiedby"                    
 [83] "individualid"                     "informationwithheld"             
 [85] "infraspecificepithet"             "institutionid"                   
 [87] "island"                           "islandgroup"                     
 [89] "language"                         "lifestage"                       
 [91] "locality"                         "locationaccordingto"             
 [93] "locationid"                       "locationremarks"                 
 [95] "materialsampleid"                 "maximumdepthinmeters"            
 [97] "minimumdepthinmeters"             "modified"                        
 [99] "municipality"                     "nameaccordingto"                 
[101] "nameaccordingtoid"                "namepublishedin"                 
[103] "namepublishedinid"                "occurrencedetails"               
[105] "occurrenceid"                     "occurrenceremarks"               
[107] "occurrencestatus"                 "originalnameusage"               
[109] "originalnameusageid"              "othercatalognumbers"             
[111] "ownerinstitutioncode"             "recordedby"                      
[113] "recordnumber"                     "references"                      
[115] "reproductivecondition"            "rights"                          
[117] "rightsholder"                     "samplesize"                      
[119] "sex"                              "source"                          
[121] "specificepithet"                  "stateprovince"                   
[123] "taxonconceptid"                   "taxonid"                         
[125] "taxonomicstatus"                  "taxonrank"                       
[127] "taxonremarks"                     "type"                            
[129] "typestatus"                       "vernacularname"                  
[131] "waterbody"                       

following Darwin Core rename the latitude and longitude columns to decimalLatitude and decimalLongitude respectively

tidydata <- rawdata
names(tidydata)[names(tidydata)=="latitude"] <- "decimalLatitude"
names(tidydata)[names(tidydata)=="longitude"] <- "decimalLongitude"
head(tidydata)

The dataset is global and needs to be trimmed to contain just the area of interest. Plot all the occurance points

library(rworldmap)
### Welcome to rworldmap ###
For a short introduction type :      vignette('rworldmap')
map <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map, xlim = c(-180, -44), ylim =c(0,80), asp = 1) #the x and y lim are the long-lat bounds of the map
points(tidydata$decimalLongitude, tidydata$decimalLatitude) #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")

now extract just the Atlantic Canada data. The lon-lat study area (which captures the whole Atlantic Canadian EEZ up to the north of Resolution Island in the Hudson Strait/ Davis Strait) is -71.0,-43.0,62.0,38.0

tidydata <- tidydata[tidydata$decimalLongitude > -71, ]
tidydata <- tidydata[tidydata$decimalLongitude < -43, ]
tidydata <- tidydata[tidydata$decimalLatitude > 38, ]
plot(map, xlim = c(-180, -44), ylim =c(0,80), asp = 1) 
points(tidydata$decimalLongitude, tidydata$decimalLatitude)

ok looks good…save what you have so far to a .csv

write.csv(tidydata, file = "../data/bio/capelin_obis_tidy.csv", row.names = FALSE)

Column removal

So there are many columns that you don’t need.. you want to keep id decimalLatitude decimalLongitude datecollected institutioncode individualcount resname originalscientificname collectioncode (this contains some info that might help with finding out gear used in the survey)

tidydata <- subset(tidydata, select = c(id, decimalLatitude, decimalLongitude, datecollected, institutioncode, individualcount, resname, originalscientificname, collectioncode))
head(tidydata)

Month year column creation

make columns for the years and month based on the datecollected column

tidydata$year <- format(as.Date(tidydata$datecollected), "%Y") #created a new column called year
tidydata$month <- format(as.Date(tidydata$datecollected), "%m") #created a new column called month
tidydata$day <- format(as.Date(tidydata$datecollected), "%d") #created a new column called day 
head(tidydata)

the year, month, day columns are characters Change to numeric

tidydata$year <- as.numeric(tidydata$year)
tidydata$month <- as.numeric(tidydata$month)
tidydata$day <- as.numeric(tidydata$day)
head(tidydata)

remove data without month/year info

count NAs in the dataset. Mainly you are interested in the datecollected column (ignore individual count - you know there is a lot missing)

missingdata <- apply(tidydata, 2, function (x) sum(is.na(x)))
missingdata
                    id        decimalLatitude       decimalLongitude 
                     0                      0                      0 
         datecollected        institutioncode        individualcount 
                     0                      0                  16202 
               resname originalscientificname         collectioncode 
                     0                      0                      0 
                  year                  month                    day 
                   771                    771                    771 

hmm interesting - you have 771 columns from year month and day with missing data, but datacollected has 0. There may be a formatting issue. To take a closer look, subset all rows where year == na

missingdatarows <- tidydata[is.na(tidydata$year), ]
head(missingdatarows)

so the NAs in the year column relate to no data (without a na value attached). Remove all rows where year == na

tidydata <- tidydata[!is.na(tidydata$year), ]
missingdata2 <- apply(tidydata, 2, function (x) sum(is.na(x)))
missingdata2
                    id        decimalLatitude       decimalLongitude 
                     0                      0                      0 
         datecollected        institutioncode        individualcount 
                     0                      0                  15445 
               resname originalscientificname         collectioncode 
                     0                      0                      0 
                  year                  month                    day 
                     0                      0                      0 

Remove any duplicate entries

The dplyr package’s distinct function removes any duplicate rows (based on all columns EXCEPT id as this is always going to be unique, and year month day as this is generated from datecollected)

library("dplyr")

Attaching package: 㤼㸱dplyr㤼㸲

The following objects are masked from 㤼㸱package:stats㤼㸲:

    filter, lag

The following objects are masked from 㤼㸱package:base㤼㸲:

    intersect, setdiff, setequal, union
tidydata <- distinct(tidydata, decimalLatitude, decimalLongitude, datecollected, institutioncode, institutioncode, individualcount, resname, originalscientificname, .keep_all = T) #the .keep_all means that id isn't excluded from the output
head(tidydata)

Institutions

Lets take a look at the institutioncode to make sure the names make sense…

tidydata$institutioncode <- as.character(tidydata$institutioncode)
whosampled <- unique(tidydata$institutioncode) #makes a variable of institutions
whosampledordered <- sort(whosampled) #just puts the list in 
whosampledordered
 [1] ""                                                  
 [2] "Bedford Institute of Oceanography (BIO)"           
 [3] "BIO"                                               
 [4] "DFO-Central and Arctic, Freshwater Institute (FWI)"
 [5] "DFO-IML"                                           
 [6] "DFO-ISDM"                                          
 [7] "DFO-NFLD"                                          
 [8] "DFO-NG"                                            
 [9] "DFO-SF"                                            
[10] "DFO-SG"                                            
[11] "DFO Gulf Fisheries Centre"                         
[12] "ICES"                                              
[13] "IML-MLI"                                           
[14] "IML_MLI"                                           
[15] "IMR"                                               
[16] "Maine DMR"                                         
[17] "NMFS-NEFSC"                                        
[18] "NOAA, NMFS, Northeast Fisheries Science Center"    
[19] "North Atlantic Fisheries Centre"                   
[20] "Northwest Atlantic Fisheries Organization (NAFO)"  
[21] "ROM"                                               
[22] "The Atlantic reference Centre"                     
[23] "The Atlantic Reference Centre (ARC)"               
[24] "USNM"                                              

Ok so a number of these names actually represent the same insitiution (e.g. DFO Regions. Some details here and the first is no institution (you might be able to figure it out though). The merges needed are as follows “Bedford Institute of Oceanography (BIO)” & “BIO” & “DFO-SF” == DFOMTMS “DFO-IML” & “IML-MLI” & “IML_MLI” & “DFO-NG” == DFOQC “DFO-NFLD” & “North Atlantic Fisheries Centre” == “DFONL” “NMFS-NEFSC” & “NOAA, NMFS, Northeast Fisheries Science Center” == NEFSC “The Atlantic reference Centre” & “The Atlantic Reference Centre (ARC)” == ARC “DFO-SG” & “DFO Gulf Fisheries Centre” == DFOGULF

and some you can just make shorter “Northwest Atlantic Fisheries Organization (NAFO)” == NAFO “DFO-ISDM” == DFOISDM “Maine DMR” == MaineDMR

tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "Bedford Institute of Oceanography (BIO)", "DFOMTMS")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "BIO", "DFOMTMS")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO-SF", "DFOMTMS")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO-IML", "DFOQC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "IML-MLI", "DFOQC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO-NG", "DFOQC")  
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "IML_MLI", "DFOQC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO-NFLD", "DFONL")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "North Atlantic Fisheries Centre", "DFONL")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "NMFS-NEFSC", "NEFSC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "NOAA, NMFS, Northeast Fisheries Science Center", "NEFSC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "The Atlantic Reference Centre (ARC)", "ARC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "The Atlantic reference Centre", "ARC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO-SG", "DFOGulf")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO Gulf Fisheries Centre", "DFOGulf")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "Northwest Atlantic Fisheries Organization (NAFO)", "NAFO")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO-Central and Arctic, Freshwater Institute (FWI)", "DFOCENARC")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "DFO-ISDM", "DFOISDM")
tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "Maine DMR", "MaineDMR")
#recheck
tidydata$institutioncode <- as.character(tidydata$institutioncode)
whosampled <- unique(tidydata$institutioncode) #makes a variable of institutions
whosampledordered <- sort(whosampled) #just puts the list in 
whosampledordered
 [1] ""          "ARC"       "DFOCENARC" "DFOGulf"   "DFOISDM"   "DFOMTMS"  
 [7] "DFONL"     "DFOQC"     "ICES"      "IMR"       "MaineDMR"  "NAFO"     
[13] "NEFSC"     "ROM"       "USNM"     

Now look at the missing institution. Use resname to see if it helps…

missinginst <- subset(tidydata, institutioncode == "")
missinginst

ok now check for unique resname…

missinginst$resname <- as.character(missinginst$resname)
missinginstunique <- unique(missinginst$resname) #makes a variable of institutions
missinginstuniquedordered <- sort(missinginstunique) #just puts the list in 
missinginstuniquedordered <- as.character(missinginstuniquedordered)
missinginstuniquedordered
[1] "Arctic Species Trend Index (ASTI) : Marine"

Ok soo looking at the OBIS metadata, the institution is the Conservation of Arctic Flora and Fauna (CAFF)

tidydata$institutioncode <- replace(tidydata$institutioncode, tidydata$institutioncode == "", "CAFF")
whosampled <- unique(tidydata$institutioncode) #makes a variable of institutions
whosampledordered <- sort(whosampled) #just puts the list in 
whosampledordered
 [1] "ARC"       "CAFF"      "DFOCENARC" "DFOGulf"   "DFOISDM"   "DFOMTMS"  
 [7] "DFONL"     "DFOQC"     "ICES"      "IMR"       "MaineDMR"  "NAFO"     
[13] "NEFSC"     "ROM"       "USNM"     

Now lets check the number of records and spatial-temporal distribution of the observations by institution code to make sure none are dodgy

first a table of how many observations each instituioncode has

library(plyr) #to use the count function
--------------------------------------------------------------------------
You have loaded plyr after dplyr - this is likely to cause problems.
If you need functions from both plyr and dplyr, please load plyr first, then dplyr:
library(plyr); library(dplyr)
--------------------------------------------------------------------------

Attaching package: 㤼㸱plyr㤼㸲

The following objects are masked from 㤼㸱package:dplyr㤼㸲:

    arrange, count, desc, failwith, id, mutate, rename, summarise,
    summarize
obs_by_ins <- count(tidydata, "institutioncode")
obs_by_ins
write.csv(obs_by_ins, file = "../output/bio/no_observations_institutioncode.csv")

ok so IMR, NAFO, ICES, & USM have very few entries (1, 1, 1, and 3 respectively)

Lets take a look at the spatial breakdown of these institutions.First all points…

map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(38, 62), asp = 1, main = "All Occurrences", col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(tidydata$decimalLongitude, tidydata$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/all_occurrences.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

Note there is one point up by iceland that you should get rid of (Icelandic population thought to be seperate from Labrador, but it is unclear if this is true or not).

Map the institutioncode == ARC only data…

ARC_obs <- tidydata[tidydata$institutioncode == "ARC", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "Arc Occurrences", col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(ARC_obs$decimalLongitude, ARC_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/ARC_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

CAFF_obs <- tidydata[tidydata$institutioncode == "CAFF", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "CAFF Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(CAFF_obs$decimalLongitude, CAFF_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/CAFF_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

DFOCENARC_obs <- tidydata[tidydata$institutioncode == "DFOCENARC", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "DFO Central & Arctic Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(DFOCENARC_obs$decimalLongitude, DFOCENARC_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/DFOCENARC_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

DFOGulf_obs <- tidydata[tidydata$institutioncode == "DFOGulf", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "DFO Gulf Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(DFOGulf_obs$decimalLongitude, DFOGulf_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/DFOGulf_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

DFOISDM_obs <- tidydata[tidydata$institutioncode == "DFOISDM", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "DFO ISDM Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(DFOISDM_obs$decimalLongitude, DFOISDM_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/DFOISDM_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

DFOMTMS_obs <- tidydata[tidydata$institutioncode == "DFOMTMS", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "DFO Maritimes Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(DFOMTMS_obs$decimalLongitude, DFOMTMS_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/DFOMTMS_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

DFONL_obs <- tidydata[tidydata$institutioncode == "DFONL", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "DFO Newfouundland & Labrador Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(DFONL_obs$decimalLongitude, DFONL_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/DFONL_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

DFOQC_obs <- tidydata[tidydata$institutioncode == "DFOQC", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "DFO Quebec Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(DFOQC_obs$decimalLongitude, DFOQC_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/DFOQC_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

ICES_obs <- tidydata[tidydata$institutioncode == "ICES", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "ICES Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(ICES_obs$decimalLongitude, ICES_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/ICES_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

IMR_obs <- tidydata[tidydata$institutioncode == "IMR", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "IMR Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(IMR_obs$decimalLongitude, IMR_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/IMR_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

MaineDMR_obs <- tidydata[tidydata$institutioncode == "MaineDMR", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "Maine DMR Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(MaineDMR_obs$decimalLongitude, MaineDMR_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/MaineDMR_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

NAFO_obs <- tidydata[tidydata$institutioncode == "NAFO", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "NAFO Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(NAFO_obs$decimalLongitude, NAFO_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/NAFO_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

NEFSC_obs <- tidydata[tidydata$institutioncode == "NEFSC", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "NEFSC Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(NEFSC_obs$decimalLongitude, NEFSC_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/NEFSC_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

ROM_obs <- tidydata[tidydata$institutioncode == "ROM", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "Royal Ontario Museum Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(ROM_obs$decimalLongitude, ROM_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/ROM_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

USNM_obs <- tidydata[tidydata$institutioncode == "USNM", ]
map2 <- getMap(resolution = "low") #creates an object called map at low resoultion
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "National Museum of Natural History Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(USNM_obs$decimalLongitude, USNM_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/USNM_occurrences_all.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

Looking at the maps, the ROM, NAFO, IMR, ICES have data next to iceland. Since NAFO, IMR, and ICES only have one data point each, you can remove these observations easily from the record…

tidydata <- tidydata[!tidydata$institutioncode == "NAFO", ]
tidydata <- tidydata[!tidydata$institutioncode == "IMR", ]
tidydata <- tidydata[!tidydata$institutioncode == "ICES", ]

Now for ROM there are more data points… Use indentify function which lets you click on a point on the plot

x11() #this opens the plot i a window you can interact with
plot(map2, xlim = c(-71, -43), ylim =c(39, 62), asp = 1, main = "Royal Ontario Museum Occurrences",  col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(ROM_obs$decimalLongitude, ROM_obs$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude"))
identify(ROM_obs$decimalLongitude, ROM_obs$decimalLatitude, labels=ROM_obs$decimalLongitude) #decimalLongitude chosen as plot identifier as the values are unique
[1] 2

The point that needs to be removed is located at -44.96667. Note this is not the full value so use some other locators to remove the row (you could just used id, but pick multiple others just to learn)

tidydata <- tidydata[!(tidydata$resname == "Fish specimens" & tidydata$datecollected == "1965-08-13 12:00:00+01"), ]

now replot all data just to check…

plot(map2, xlim = c(-71, -43), ylim =c(38, 62), asp = 1, main = "All Occurrences without Iceland", col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(tidydata$decimalLongitude, tidydata$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")
dev.copy(png, "../output/bio/all_occurrences_less_iceland.png") #this prints a png of the plot
png 
  3 
dev.off() #this turns off the print command
png 
  2 

great! write what you have so far to a csv

write.csv(tidydata, file = "../data/bio/capelin_obis_tidy.csv", row.names = FALSE)

Remove dates you don’t have environmental data for

The BIOMER dataset starts in 1998-01 (GLORYS 1993), so cut all occurrences prior to 1998-01

tidydata <- tidydata[tidydata$year >= 1998, ]

and write to a csv…

write.csv(tidydata, file = "../data/bio/capelin_obis_tidy.csv", row.names = FALSE)

Adding new (non-environmental) data to the file

There are some more columns you want to add… - Occurrence - presence/background (1/0) - NAFO region - Gear type - Unique Cell ID (based on the environmental data)

so not to mess with tidydata, create a new variable and write a new .csv

adddata <- tidydata
write.csv(adddata, file = "../data/bio/capelin_additional_tidy.csv", row.names = FALSE)

first create a new column for Occurence, and populate with “1” (because these are all presences)

adddata$occurrence <- "1"
head(adddata)

Add NAFO Region occurrence is from

NAFO Zones shapefile obtained from NAFO

library(rgdal)
rgdal: version: 1.3-4, (SVN revision 766)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
 Path to GDAL shared files: C:/Users/bunny/Documents/GitHub/Chapter_1/packrat/lib/x86_64-w64-mingw32/3.5.1/rgdal/gdal
 GDAL binary built with GEOS: TRUE 
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: C:/Users/bunny/Documents/GitHub/Chapter_1/packrat/lib/x86_64-w64-mingw32/3.5.1/rgdal/proj
 Linking to sp version: 1.3-1 

Great. Lets see if any are missing a NAFO Zone. But first, write to a csv and reload as the data is now some wierd ‘spatial points dataframe’…

write.csv(adddata, "../data/bio/capelin_additional_tidy.csv", row.names=FALSE)
adddata <- read.csv("../data/bio/capelin_additional_tidy.csv")
nafo_na <- subset(adddata, is.na(adddata$nafo_zone))
nafo_na

Uh oh there is a lot. A bet a bunch of them are in the Hudson Strait (which is outside the NAFO Zone).Map the nafo_na points…

plot(map2, xlim = c(-71, -43), ylim =c(38, 62), asp = 1, main = "Occurences missing a NAFO Zone", col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(nafo_na$decimalLongitude, nafo_na$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")

ok yes - Hudson Strait has many, but there are some near the coast that are probably just missed out due to minor differences in the point location/shapefile boundaries. Start with the Hudson Strait ones as this is easy - anything above 56N, nafo_zone == “HudsonStrait”

adddata$nafo_zone <- as.character(adddata$nafo_zone)
adddata[is.na(adddata)] <- "xx"
adddata$nafo_zone[adddata$nafo_zone == "xx" & adddata$decimalLatitude > 56] <- "HudsonStrait"

and map to check

nafo_na <- subset(adddata, nafo_zone == "xx")
plot(map2, xlim = c(-71, -43), ylim =c(38, 62), asp = 1, main = "Occurences missing a NAFO Zone", col = "cornsilk") #the x and y lim are the long-lat bounds of the map
points(nafo_na$decimalLongitude, nafo_na$decimalLatitude, col = "red") #this adds points to the mapet", xlab = "Longitude", ylab = "Latitude")

so now i need to account for the others (either as occuring on land or just in an area that is missing a NAFO Zone tag) which is more tricky… i might just do this bit in ArcGIS quickly.

write.csv(adddata, file = "../data/bio/capelin_additional_tidy.csv", row.names = FALSE)

So in ArcGIS I saw that these points fall on land. Some are extremely close to the coast, some further inland. There are only 132 of thesepoints, so I will just delete them from the database.

adddata$nafo_zone[adddata$nafo_zone == "xx"] <- NA #make all xx values NA
adddata <- adddata[!is.na(adddata$nafo_zone), ]
write.csv(adddata, file = "../data/bio/capelin_additional_tidy.csv", row.names = FALSE)

Gear type

To get this information, I need to look at the collectioncode details and the OBIS metadata for each resname and then add.

adddata$gear <- "x" #create a new column called gear and populate with x
#now give a list of the resnames...
whichres <- unique(adddata$resname) #makes a variable of institutions
whichresordered <- sort(whichres) #just puts the list in 
whichresordered
 [1] Arctic Species Trend Index (ASTI) : Marine                                                                                   
 [2] Atlantic Reference Centre Museum of Canadian Atlantic Organisms - Invertebrates and Fishes Data                              
 [3] Atlantic Zone Monitoring Program Maritimes Region (AZMP) plankton datasets. In: Fisheries and Oceans Canada - BioChem archive
 [4] BioChem zooplankton samples from the Gully, 2006-2007                                                                        
 [5] BioChem: DFO Atlantic Zone Monitoring Program plankton datasets - Newfoundland and Labrador Region (OBIS Canada)             
 [6] BioChem: Sameoto zooplankton collection                                                                                      
 [7] DFO Central and Arctic Multi-species Stock Assessment Surveys                                                                
 [8] DFO Gulf Region Groundfish Research Vessel Surveys                                                                           
 [9] DFO Maritimes Research Vessel Trawl Surveys Fish Observations                                                                
[10] DFO Newfoundland and Labrador Region Ecosystem Trawl Surveys                                                                 
[11] DFO Quebec Region Multispecies bottom trawl surveys                                                                          
[12] Fish specimens                                                                                                               
[13] Ichthyology Collection - Royal Ontario Museum                                                                                
[14] Maine Department of Marine Resources Inshore Trawl Survey 2000–2009                                                        
[15] Northeast Fisheries Science Center Bottom Trawl Survey Data                                                                  
[16] Northern Gulf of St. Lawrence Fishes                                                                                         
16 Levels: Arctic Species Trend Index (ASTI) : Marine ...

Arctic Species Trend Index (ASTI) : Marine. No gear details available

asti <- subset(adddata, resname == "Arctic Species Trend Index (ASTI) : Marine")
asti$collectioncode <- as.character(asti$collectioncode)
asti_col <- unique(asti$collectioncode) #makes a variable of institutions
asti_colordered <- sort(asti_col) #just puts the list in 
asti_colordered
[1] ""

there is no information in the collection code. The Metadata on OBIS also gives no details. gear = NA

adddata$gear[adddata$resname == "Arctic Species Trend Index (ASTI) : Marine"] <- "NA"

Atlantic Reference Centre Museum of Canadian Atlantic Organisms - Invertebrates and Fishes Data.

arcm <- subset(adddata, resname == "Atlantic Reference Centre Museum of Canadian Atlantic Organisms - Invertebrates and Fishes Data")
arcm$collectioncode <- as.character(arcm$collectioncode)
arcm_col <- unique(arcm$collectioncode) #makes a variable of institutions
arcm_colordered <- sort(arcm_col) #just puts the list in 
arcm_colordered
[1] "ARC"

No gear details in collectioncode. The Metadata on OBIS also gives no details. gear = NA

adddata$gear[adddata$resname == "Atlantic Reference Centre Museum of Canadian Atlantic Organisms - Invertebrates and Fishes Data"] <- "NA"

Atlantic Zone Monitoring Program Maritimes Region (AZMP) plankton datasets. In: Fisheries and Oceans Canada - BioChem archive.

azmpmar <- subset(adddata, resname == "Atlantic Zone Monitoring Program Maritimes Region (AZMP) plankton datasets. In: Fisheries and Oceans Canada - BioChem archive")
azmpmar$collectioncode <- as.character(azmpmar$collectioncode)
azmpmar_col <- unique(azmpmar$collectioncode) #makes a variable of institutions
azmpmar_colordered <- sort(azmpmar_col) #just puts the list in 
azmpmar_colordered
[1] "AZMP-MAR-2003"           "AZMP-MARgroundfish-2000" "AZMP-MARgroundfish-2001" "AZMP-MARgroundfish-2003" "AZMP-MARgroundfish-2004"
[6] "AZMP-MARgroundfish-2006" "AZMP-MARgroundfish-2008"

No gear details in collectioncode. The metadata on OBIS indicates vertical plankton tow

adddata$gear[adddata$resname == "Atlantic Zone Monitoring Program Maritimes Region (AZMP) plankton datasets. In: Fisheries and Oceans Canada - BioChem archive"] <- "vertical_plankton_tow"

BioChem zooplankton samples from the Gully, 2006-2007.

biogul <- subset(adddata, resname == "BioChem zooplankton samples from the Gully, 2006-2007")
biogul$collectioncode <- as.character(biogul$collectioncode)
biogul_col <- unique(biogul$collectioncode) #makes a variable of institutions
biogul_colordered <- sort(biogul_col) #just puts the list in 
biogul_colordered
[1] "Gully Plankton Ringnet Samples 2006-2007"

Along with the OBIS metadata, indicates gear = vertical plankton tow

adddata$gear[adddata$resname == "BioChem zooplankton samples from the Gully, 2006-2007"] <- "vertical_plankton_tow"

BioChem: DFO Atlantic Zone Monitoring Program plankton datasets - Newfoundland and Labrador Region (OBIS Canada).

azmpnl <- subset(adddata, resname == "BioChem: DFO Atlantic Zone Monitoring Program plankton datasets - Newfoundland and Labrador Region (OBIS Canada")
azmpnl$collectioncode <- as.character(azmpnl$collectioncode)
azmpnl_col <- unique(azmpnl$collectioncode) #makes a variable of institutions
azmpnl_colordered <- sort(azmpnl_col) #just puts the list in 
azmpnl_colordered
character(0)

No details in collectioncode. Obis metadata indicates gear = vertical plankton tow

adddata$gear[adddata$resname == "BioChem: DFO Atlantic Zone Monitoring Program plankton datasets - Newfoundland and Labrador Region (OBIS Canada)"] <- "vertical_plankton_tow"

BioChem: Sameoto zooplankton collection.Vertical plankton tow

biosam <- subset(adddata, resname == "BioChem: Sameoto zooplankton collection")
biosam$collectioncode <- as.character(biosam$collectioncode)
biosam_col <- unique(biosam$collectioncode) #makes a variable of institutions
biosam_colordered <- sort(biosam_col) #just puts the list in 
biosam_colordered
[1] "BIO-Sameoto BIONESS samples"

Insufficient details in collectioncode. Obis metadata indicates gear = vertical plankton tow

adddata$gear[adddata$resname == "BioChem: Sameoto zooplankton collection"] <- "vertical_plankton_tow"

DFO Central and Arctic Multi-species Stock Assessment Surveys. A

dfocas <- subset(adddata, resname == "DFO Central and Arctic Multi-species Stock Assessment Surveys")
dfocas$collectioncode <- as.character(dfocas$collectioncode)
dfocas_col <- unique(dfocas$collectioncode) #makes a variable of institutions
dfocas_colordered <- sort(dfocas_col) #just puts the list in 
dfocas_colordered
[1] "DFOSurvey_Modified Alfredo-03"               "DFOSurvey_Modified Cosmos 2600"             
[3] "DFOSurvey_Modified Modified (21\") Campelen" "DFOSurvey_Modified Standard (14\") Campelen"

ok these are all types of bottom trawl.

adddata$gear[adddata$resname == "DFO Central and Arctic Multi-species Stock Assessment Surveys" & adddata$collectioncode == "DFOSurvey_Modified Alfredo-03"] <- "bottom_trawl_alfredo_03"
adddata$gear[adddata$resname == "DFO Central and Arctic Multi-species Stock Assessment Surveys" & adddata$collectioncode == "DFOSurvey_Modified Cosmos 2600"] <- "bottom_trawl_cosmos_2600"
adddata$gear[adddata$resname == "DFO Central and Arctic Multi-species Stock Assessment Surveys" & adddata$collectioncode == "DFOSurvey_Modified Modified (21\") Campelen"] <- "bottom_trawl_campelen_21"
adddata$gear[adddata$resname == "DFO Central and Arctic Multi-species Stock Assessment Surveys" & adddata$collectioncode == "DFOSurvey_Modified Standard (14\") Campelen"] <- "bottom_trawl_campelen_14"

DFO Gulf Region Groundfish Research Vessel Surveys.

dfogulfas <- subset(adddata, resname == "DFO Gulf Region Groundfish Research Vessel Surveys")
dfogulfas$collectioncode <- as.character(dfogulfas$collectioncode)
dfogulfas_col <- unique(dfogulfas$collectioncode) #makes a variable of institutions
dfogulfas_colordered <- sort(dfogulfas_col) #just puts the list in 
dfogulfas_colordered
[1] "ECOSYSTEM"

no gear details in collection code. OBIS metadata indicates Three survey vessels and two types of bottom-trawls were used prior to 2003: the E. E. Prince from 1971-1985 using a Yankee 36 trawl, the Lady Hammond from 1985-1991 and the Alfred Needler from 1992-2002, both using a Western IIA trawl. Due to a fire on the Needler, the 2003 survey was conducted by its sister-ship, the Templeman using the Western IIA trawl. This survey started late and was incomplete. The survey was conducted by both the Needler and the Teleost in 2004 and 2005 and by the Teleost since then, using the Western IIA trawl. Note you have not captured ship information above so leave it out here. Your data is 1998 onwards to the gear for all = bottom_trawl_western_IIA

adddata$gear[adddata$resname == "DFO Gulf Region Groundfish Research Vessel Surveys"] <- "bottom_trawl_western_IIA"

DFO Maritimes Research Vessel Trawl Surveys Fish Observations.

dfomas <- subset(adddata, resname == "DFO Maritimes Research Vessel Trawl Surveys Fish Observations")
dfomas$collectioncode <- as.character(dfomas$collectioncode)
dfomas_col <- unique(dfomas$collectioncode) #makes a variable of institutions
dfomas_colordered <- sort(dfomas_col) #just puts the list in 
dfomas_colordered
[1] "4VWCOD"          "4VWCOD_TELEOST"  "COMPARE"         "GEORGES"         "GEORGES_TELEOST" "SUMMER"          "SUMMER_TELEOST" 

insuffient information. OBIS metadata just indicates “a variety of trawl gear”. gear = “bottom_trawl”

adddata$gear[adddata$resname == "DFO Maritimes Research Vessel Trawl Surveys Fish Observations"] <- "bottom_trawl"

DFO Newfoundland and Labrador Region Ecosystem Trawl Surveys

dfonas <- subset(adddata, resname == "DFO Newfoundland and Labrador Region Ecosystem Trawl Surveys")
dfonas$collectioncode <- as.character(dfonas$collectioncode)
dfonas_col <- unique(dfonas$collectioncode) #makes a variable of institutions
dfonas_colordered <- sort(dfonas_col) #just puts the list in 
dfonas_colordered
[1] "BT_standard_sets"

More useful, OBIS metadata indicates “Starting in the fall of 1995 surveys have been conducted using a Campelen 1800 trawl fitted with rock-hopper foot gear.” gear = bottom_trawl_campelen_1800

adddata$gear[adddata$resname == "DFO Newfoundland and Labrador Region Ecosystem Trawl Surveys"] <- "bottom_trawl_campelen_1800"

DFO Quebec Region Multispecies bottom trawl surveys

dfoqas <- subset(adddata, resname == "DFO Quebec Region Multispecies bottom trawl surveys")
dfoqas$collectioncode <- as.character(dfoqas$collectioncode)
dfoqas_col <- unique(dfoqas$collectioncode) #makes a variable of institutions
dfoqas_colordered <- sort(dfoqas_col) #just puts the list in 
dfoqas_colordered
[1] "RELEVES_RECHERCHE"

no gear details in collectioncode. OBIS metadata indicates Campelen 1800. gear = bottom_trawl_campelen_1800

adddata$gear[adddata$resname == "DFO Quebec Region Multispecies bottom trawl surveys"] <- "bottom_trawl_campelen_1800"

Fish specimens

fishsp <- subset(adddata, resname == "Fish specimens")
fishsp$collectioncode <- as.character(fishsp$collectioncode)
fishsp_col <- unique(fishsp$collectioncode) #makes a variable of institutions
fishsp_colordered <- sort(fishsp_col) #just puts the list in 
fishsp_colordered
[1] "Ichthyology"

no gear detail in collectioncode. OBIS metadata indicates these are museum records. gear = NA

adddata$gear[adddata$resname == "Fish specimens"] <- "NA"

Ichthyology Collection - Royal Ontario Museum

iccol <- subset(adddata, resname == "Ichthyology Collection - Royal Ontario Museum")
iccol$collectioncode <- as.character(iccol$collectioncode)
iccol_col <- unique(iccol$collectioncode) #makes a variable of institutions
iccol_colordered <- sort(iccol_col) #just puts the list in 
iccol_colordered
[1] "Fishes"

no gear details in collectioncode. OBIS metadata indicates museum records. gear = NA

adddata$gear[adddata$resname == "Ichthyology Collection - Royal Ontario Museum"] <- "NA"

Maine Department of Marine Resources Inshore Trawl Survey 2000–2009

mdmr <- subset(adddata, resname == "Maine Department of Marine Resources Inshore Trawl Survey 2000–2009")
mdmr$collectioncode <- as.character(mdmr$collectioncode)
mdmr_col <- unique(mdmr$collectioncode) #makes a variable of institutions
mdmr_colordered <- sort(mdmr_col) #just puts the list in 
mdmr_colordered
[1] "ME - NH Inshore Groundfish Trawl Survey"

Insufficient infomation in collectioncode. OBIS metadata indicates “a modified version of the shrimp net used in Maine waters. It was designed by the vessel owner and net designer Jeff Flagg to fish for a variety of near-bottom dwelling species without targeting any specific component” gear-type = “bottom_trawl”

adddata$gear[adddata$resname == "Maine Department of Marine Resources Inshore Trawl Survey 2000–2009"] <- "bottom_trawl"

Northeast Fisheries Science Center Bottom Trawl Survey Data

nefsu <- subset(adddata, resname == "Northeast Fisheries Science Center Bottom Trawl Survey Data")
nefsu$collectioncode <- as.character(nefsu$collectioncode)
nefsu_col <- unique(nefsu$collectioncode) #makes a variable of institutions
nefsu_colordered <- sort(nefsu_col) #just puts the list in 
nefsu_colordered
[1] "SPRING NMFS NEFSC BOTTOM TRAWL SURVEY"

insufficient detail in collection code. OBIS metadata indicates “bottom trawl gear”. gear = “bottom_trawl”

adddata$gear[adddata$resname == "Northeast Fisheries Science Center Bottom Trawl Survey Data"] <- "bottom_trawl"

Northern Gulf of St. Lawrence Fishes

ngsl <- subset(adddata, resname == "Northern Gulf of St. Lawrence Fishes")
ngsl$collectioncode <- as.character(ngsl$collectioncode)
ngsl_col <- unique(ngsl$collectioncode) #makes a variable of institutions
ngsl_colordered <- sort(ngsl_col) #just puts the list in 
ngsl_colordered
[1] "Poisson"

no gear details in collectioncode. OBIS metadata indicates “Sampling methods used ranged from fish traps and seine nets on the coasts to offshore trawling”. gear = NA

adddata$gear[adddata$resname == "Northern Gulf of St. Lawrence Fishes"] <- "NA"

ok check to see if all of gear is done (ie if there are any x left)

gearcheck <- subset(adddata, gear == "x")
gearcheck

yay - all done.

see who sampled in which year and month

year

with(adddata, table(year, institutioncode))
      institutioncode
year   ARC CAFF DFOCENARC DFOGulf DFOISDM DFOMTMS DFONL DFOQC MaineDMR NEFSC ROM
  1998   1    1         0      48       1      21   585    70        0     1   0
  1999   0    1         0      90       1      74   507     0        0     0   0
  2000  18    1         0      99      15      58   536     0        0     0   0
  2001   0    1         0      52       1      44   549     0        0     0   0
  2002   7    1         0     104       1      52   496     0        0     0   0
  2003   0    1         0      43       3      42   579     0        0     0   0
  2004   0    1         0      94       2      24   671   177        0     0   0
  2005   1    1        14     109       0      83   473   219        7     0   0
  2006   4    1        11      78       4      80   482   236        6     0   0
  2007   2    1        42      87       1      37   467   234        0     0   2
  2008   0    1        10      82       5      38   478   265        1     0   0
  2009   0    1        14      78       0      30   512   133        3     0   0
  2010   1    1        10      95       0      44   535   111        0     0   0
  2011   0    1        22      77       0      14   479   141        0     0   0
  2012   0    1         8      86       0      10     0   152        0     0   0
  2013   2    0        18      69       0      21     0   129        0     0   0
  2014   1    0        22     101       0       6     0     0        0     0   0
  2015   3    0        12       0       0       0     0     0        0     0   0

month

inst_by_mt <- with(adddata, table(month, institutioncode))
write.csv(inst_by_mt, file = "../output/bio/institutioncode_by_mth.csv")

create a unique cell ID

A unique cell ID layer has been created in the environmental_data_preperation.Rmd. Now you want to extract the value of that layer to the .csv you are creating…

Load the env. data

and just grab the attributes of the cell_layer

cell_layer
class       : RasterLayer 
dimensions  : 112, 102, 11424  (nrow, ncol, ncell)
resolution  : 25000, 25000  (x, y)
extent      : -1012223, 1537777, -228779.7, 2571220  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=aea +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-60 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
data source : C:\Users\bunny\Documents\GitHub\Chapter_1\output\env\glo_unique_cell.tif 
names       : glo_unique_cell 
values      : 1, 6729  (min, max)

The occurrence data needs to be converted into spatialpoints dataframe

library(sp)
xy <- adddata[ ,c(3,2)] #3 = decimalLongitude, 2 = decimalLatitude
adddata_aea <- SpatialPointsDataFrame(coords = xy, data = adddata, proj4string = CRS("+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"))
adddata_aea
class       : SpatialPointsDataFrame 
features    : 11578 
extent      : -70.573, -45.53, 41.53367, 68.587  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0 
variables   : 16
names       :        id, decimalLatitude, decimalLongitude,          datecollected, institutioncode, individualcount,                                    resname, originalscientificname, collectioncode, year, month, day, occurrence,    nafo_zone, optional, ... 
min values  :  12115310,        41.53367,        -45.53000, 1998-04-01 12:00:00+02,             ARC,               0, Arctic Species Trend Index (ASTI) : Marine,      Mallotus villosus,               , 1998,     1,   1,          1,           0A,     TRUE, ... 
max values  : 386782015,        68.58700,        -70.57300, 2015-11-27 12:00:00+01,             ROM,              xx,       Northern Gulf of St. Lawrence Fishes,      Mallotus villosus, SUMMER_TELEOST, 2015,    12,  31,          1, HudsonStrait,     TRUE, ... 
adddata_aea <- spTransform(adddata_aea, CRS = "+proj=aea +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-60 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs") #note -60 used to be -91. Changed to 'straighten up'
adddata_aea
class       : SpatialPointsDataFrame 
features    : 11578 
extent      : -858219.4, 1068577, 197997.9, 3188919  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=aea +lat_1=50 +lat_2=70 +lat_0=40 +lon_0=-60 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs +towgs84=0,0,0 
variables   : 16
names       :        id, decimalLatitude, decimalLongitude,          datecollected, institutioncode, individualcount,                                    resname, originalscientificname, collectioncode, year, month, day, occurrence,    nafo_zone, optional, ... 
min values  :  12115310,        41.53367,        -45.53000, 1998-04-01 12:00:00+02,             ARC,               0, Arctic Species Trend Index (ASTI) : Marine,      Mallotus villosus,               , 1998,     1,   1,          1,           0A,     TRUE, ... 
max values  : 386782015,        68.58700,        -70.57300, 2015-11-27 12:00:00+01,             ROM,              xx,       Northern Gulf of St. Lawrence Fishes,      Mallotus villosus, SUMMER_TELEOST, 2015,    12,  31,          1, HudsonStrait,     TRUE, ... 

and plot and Write the transformed species data to a new csv (this will also have the coordinates in meters - note meters are under decimalLongitude1 and decimalLatitude1)…

plot(adddata_aea, axes=TRUE, cex.axis=.95)

write.csv(adddata_aea, file = "../output/bio/data_aea.csv", row.names = FALSE)

Ok now plot the env. and point data…

plot(cell_layer)
points(adddata_aea$decimalLongitude, adddata_aea$decimalLatitude)

ok now the next step is to extract the unique cell value and add to each of the points then write a .csv then convert back to a normal dataframe

adddata_aea$cell_id <- extract(x=cell_layer, y = adddata_aea)
write.csv(adddata_aea, file = "../output/bio/data_aea_cell.csv", row.names = FALSE)
data_aea <- as.data.frame(adddata_aea)
head(data_aea)

looking at the header data, there seems to be some new columns created on the way…

colnames(data_aea)
 [1] "id"                     "decimalLatitude"        "decimalLongitude"       "datecollected"          "institutioncode"       
 [6] "individualcount"        "resname"                "originalscientificname" "collectioncode"         "year"                  
[11] "month"                  "day"                    "occurrence"             "nafo_zone"              "optional"              
[16] "gear"                   "cell_id"                "decimalLongitude.1"     "decimalLatitude.1"     

I don’t want “optional” - get rid of it!

data_aea <- subset(data_aea, select = -c(optional))
colnames(data_aea)
 [1] "id"                     "decimalLatitude"        "decimalLongitude"       "datecollected"          "institutioncode"       
 [6] "individualcount"        "resname"                "originalscientificname" "collectioncode"         "year"                  
[11] "month"                  "day"                    "occurrence"             "nafo_zone"              "gear"                  
[16] "cell_id"                "decimalLongitude.1"     "decimalLatitude.1"     
write.csv(adddata_aea, file = "../output/bio/data_aea_cell.csv", row.names = FALSE)

Add AMO Data

The data has been prepared as per the environmental_data_preperation.Rmd

amo <- read.csv("../output/env/amo.csv", header=TRUE)
head(amo)

So you want.. - AMO value at sampling month/year - AMO value at previous sampling month/year - AMO phase at previous winter (because the winter values are thought to be a major driver of ocean conditions in the following spring, summer, and autumn)

change month col names to numeric

names(amo)[2:13] = c("1", "2","3", "4", "5", "6", "7", "8", "9", "10", "11", "12")
head(amo)

Start with the month data first…subset cols 1:13 (where the year and month data are held)

amo_yrmt <- amo[ ,1:13]
amo_yrmt
amo_yrmt <- reshape(amo_yrmt, 
  varying = c("1", "2","3", "4", "5", "6", "7", "8", "9", "10", "11", "12"),
  v.names = "value",
  direction = "long")
amo_yrmt <- amo_yrmt[order(amo_yrmt$year),]
amo_yrmt

rename time to month.. and value to amo_sample

colnames(amo_yrmt)[2] <- "month"
colnames(amo_yrmt)[3] <- "amo_sample"
amo_yrmt

now match the year and the month in the two dataframes, and populate the species dataset (data_aea) with amo_sample

data_aea <- merge(x = data_aea, y = amo_yrmt[ , c("year", "month", "amo_sample")], by = c("year", "month"), all.x = TRUE)
data_aea

ok next - AMO value at previous sampling month/year

shift the amo_sample column down by 1…

library(useful)
Loading required package: ggplot2
amo_yrmt <- shift.column(data = amo_yrmt, columns = "amo_sample", up = FALSE)
amo_yrmt

Note the shifted values are in a new column called amo_sample.Shifted. rename to amo_prev

colnames(amo_yrmt)[colnames(amo_yrmt)=="amo_sample.Shifted"] <- "amo_prev"
amo_yrmt
write.csv(amo_yrmt, "../output/env/amo_prev.csv", row.names = FALSE) #for some reason i need to write to a csv and reload for the next step to work properly

now grab the data…

amo_prev <- read.csv("../output/env/amo_prev.csv")
data_aea <- merge(x = data_aea, y = amo_prev[ , c("year", "month", "amo_prev")], by = c("year", "month"), all.x = TRUE)
data_aea

and now - AMO phase at previous winter (because the winter values are thought to be a major driver of ocean conditions in the following spring, summer, and autumn)

same process as before - shift row then match

But first!

You need to extract the seasonal values from the amo dataset

amo_winter <- subset(amo, select = c("year", "WinterAvg"))
amo_winter

now shift the winter average data

amo_winter <- shift.column(data = amo_winter, columns = "WinterAvg", up = FALSE)
amo_winter
write.csv(amo_winter, "../output/env/amo_winter.csv", row.names = FALSE) #for some reason need to save to csv then reload in the next step...

remember your shifted column is called WinterAvg.Shifted

now extract the WinterAvg.Shifted values to the species dataset

amo_winter <- read.csv("../output/env/amo_winter.csv")
data_aea <- merge(x = data_aea, y = amo_winter[ , c("year", "WinterAvg.Shifted")], by = c("year"), all.x = TRUE)
colnames(data_aea)[colnames(data_aea)=="WinterAvg.Shifted"] <- "amo_winter" #change the colname
data_aea

ok and write a csv

write.csv(data_aea,"../output/bio/data_aea_cell_amo.csv", row.names = FALSE)

NAO values

The data has been prepared as per the environmental_data_preperation.Rmd

nao <- read.csv("../output/env/nao.csv", header=TRUE)
head(nao)

So you want.. - AMO value at sampling month/year - AMO value at previous sampling month/year - AMO phase at previous winter (because the winter values are thought to be a major driver of ocean conditions in the following spring, summer, and autumn)

change month col names to just numeric

names(nao)[2:13] = c("1", "2","3", "4", "5", "6", "7", "8", "9", "10", "11", "12")
head(nao)

Start with the month data first…subset cols 1:13 (where the year and month data are held)

nao_yrmt <- nao[ ,1:13]
nao_yrmt
nao_yrmt <- reshape(nao_yrmt, 
  varying = c("1", "2","3", "4", "5", "6", "7", "8", "9", "10", "11", "12"),
  v.names = "value",
  direction = "long")
nao_yrmt <- nao_yrmt[order(amo_yrmt$year),]
nao_yrmt

rename time to month.. and value to nao_sample

colnames(nao_yrmt)[2] <- "month"
colnames(nao_yrmt)[3] <- "nao_sample"
nao_yrmt

now match the year and the month in the two dataframes, and populate the species dataset (data_aea) with nao_sample

data_aea <- merge(x = data_aea, y = nao_yrmt[ , c("year", "month", "nao_sample")], by = c("year", "month"), all.x = TRUE)
data_aea

ok next - NAO value at previous sampling month/year

shift the nao_sample column down by 1…

library(useful)
nao_yrmt <- shift.column(data = nao_yrmt, columns = "nao_sample", up = FALSE)
nao_yrmt

Note the shifted values are in a new column called amo_sample.Shifted. rename to amo_prev

colnames(nao_yrmt)[colnames(nao_yrmt)=="nao_sample.Shifted"] <- "nao_prev"
nao_yrmt
write.csv(nao_yrmt, "../output/env/nao_prev.csv", row.names = FALSE) #for some reason i need to write to a csv and reload for the next step to work properly

now grab the data…

nao_prev <- read.csv("../output/env/nao_prev.csv")
data_aea <- merge(x = data_aea, y = nao_prev[ , c("year", "month", "nao_prev")], by = c("year", "month"), all.x = TRUE)
data_aea

and now - NAO phase at previous winter (because the winter values are thought to be a major driver of ocean conditions in the following spring, summer, and autumn)

same process as before - shift row then match

But first!

You need to extract the seasonal values from the NAO dataset

nao_winter <- subset(nao, select = c("year", "WinterAvg"))
nao_winter

now shift the winter average data

nao_winter <- shift.column(data = nao_winter, columns = "WinterAvg", up = FALSE)
nao_winter
write.csv(nao_winter, "../output/env/nao_winter.csv", row.names = FALSE) #for some reason need to save to csv then reload in the next step...

remember your shifted column is called WinterAvg.Shifted

now extract the WinterAvg.Shifted values to the species dataset

nao_winter <- read.csv("../output/env/nao_winter.csv")
data_aea <- merge(x = data_aea, y = nao_winter[ , c("year", "WinterAvg.Shifted")], by = c("year"), all.x = TRUE)
colnames(data_aea)[colnames(data_aea)=="WinterAvg.Shifted"] <- "nao_winter" #change the colname
data_aea

ok and write a csv

write.csv(data_aea,"../output/bio/data_aea_cell_amo_nao.csv", row.names = FALSE)

warm/cold year

The warm/cold year index will be taken from a DFO CSAS report

LS0tDQp0aXRsZTogImJpb2xvZ2ljYWwgZGF0YSBwcmVwZXJhdGlvbiINCmF1dGhvcjogIlNhbWFudGhhIEFuZHJld3MiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIE92ZXJ2aWV3DQpQcmVwZXJhdGlvbiBvZiB0aGUgY2FwZWxpbiAoKk1hbGxvdHVzIHZpbGxvc3VzKikgZGF0YSBvYnRhaW5lZCBmcm9tIFtPQklTXSh3d3cuaW9iaXMub3JnKS4gVGhpcyBkYXRhYmFzZSBzaG93cyB0aGUgZ2xvYmFsIG9jY3VyYW5jZSBvZiBjYXBlbGluLiANCg0KQSBub3RlIHRvIGFueW9uZSB3aG8gbWlnaHQgaGFwcGVuIHRvIHN0dW1ibGUgYWNyb3NzIHRoaXMuLi4gSSBhbSBhIGJlZ2lubmVyIGluIFIgYW5kIGhhdmUgaGFkIG5vIGV4cG9zdXJlIHRvIHNpbWlsYXIgbGFuZ3VhZ2VzLiBUaGUgY29kZSBoZXJlaW4gaXMgdW5saWtlbHkgdG8gYmUgZWxlZ2FudCBhbmQgdGhlcmUgaXMgbGlrZWx5IG1vcmUgZWZmaWNpZW50IHdheXMgb2YgcnVubmluZyB0aGUgY29kZS4NCg0KQnVpbHQgd2l0aCAnciBnZXRSdmVyc2lvbigpJy4NCg0KIyBQYWNrYWdlIGRlcGVuZGVuY2llcw0KWW91IGNhbiBsb2FkIHRoZW0gdXNpbmcgdGhlIGZvbGxvd2luZyBjb2RlIHdoaWNoIHVzZXMgYSBmdW5jdGlvbiBjYWxsZWQgW2lwYWtdKGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL3N0ZXZlbndvcnRoaW5ndG9uLzMxNzgxNjMpLiANCk5vdGUgdGhpcyBmdW5jdGlvbiBjaGVja3MgdG8gc2VlIGlmIHRoZSBwYWNrYWdlcyBhcmUgaW5zdGFsbGVkIGZpcnN0Lg0KVGgNCmBgYHtyIHByZS1pbnN0YWxsIHBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFfQ0KcGFja2FnZXMgPC0gYygicGFja3JhdCIsICJyd29ybGRtYXAiLCAiZHBseXIiLCJwbHlyIiwgInJnZGFsIiwgInNwIiwgInJhc3RlciIsICJ0aWJibGUiLCAidXNlZnVsIikNCnNvdXJjZSgiLi4vc3JjL2lwYWsuUiIpDQppcGFrKHBhY2thZ2VzKQ0Kc3VwcHJlc3NNZXNzYWdlcyhpcGFrKQ0KYGBgDQoNCiMgUmF3IERhdGEgQ2xlYW4NCkxvYWQgdGhlIHJhdyBkYXRhLCB0aGVuIGNoZWNrIHVzZSBoZWFkKCkgdG8gY2hlY2sgaXQgbG9va3Mgb2ssIHRoZW4gbmFtZXMoKSB0byBzZWUgYWxsIHRoZSBjb2x1bW4gbmFtZXMNCmBgYHtyIGxvYWQgcmF3IGRhdGF9DQpyYXdkYXRhIDwtIHJlYWQuY3N2KCIuLi9kYXRhL2Jpby9jYXBlbGluX29iaXNfcmF3LmNzdiIpDQpoZWFkKHJhd2RhdGEpIA0KbmFtZXMocmF3ZGF0YSkNCmBgYA0KDQpmb2xsb3dpbmcgW0RhcndpbiBDb3JlXShodHRwOi8vcnMudGR3Zy5vcmcvZHdjL3Rlcm1zLykgcmVuYW1lIHRoZSBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGNvbHVtbnMgdG8gZGVjaW1hbExhdGl0dWRlIGFuZCBkZWNpbWFsTG9uZ2l0dWRlIHJlc3BlY3RpdmVseQ0KYGBge3IgZGF3aW4gY29yZSBuYW1pbmcgY29udmVudGlvbn0NCnRpZHlkYXRhIDwtIHJhd2RhdGENCm5hbWVzKHRpZHlkYXRhKVtuYW1lcyh0aWR5ZGF0YSk9PSJsYXRpdHVkZSJdIDwtICJkZWNpbWFsTGF0aXR1ZGUiDQpuYW1lcyh0aWR5ZGF0YSlbbmFtZXModGlkeWRhdGEpPT0ibG9uZ2l0dWRlIl0gPC0gImRlY2ltYWxMb25naXR1ZGUiDQpoZWFkKHRpZHlkYXRhKQ0KYGBgDQoNClRoZSBkYXRhc2V0IGlzIGdsb2JhbCBhbmQgbmVlZHMgdG8gYmUgdHJpbW1lZCB0byBjb250YWluIGp1c3QgdGhlIGFyZWEgb2YgaW50ZXJlc3QuIA0KUGxvdCBhbGwgdGhlIG9jY3VyYW5jZSBwb2ludHMNCmBgYHtyIG1hcCBhbGwgb2NjdXJyZW5jZSBwb2ludHN9DQpsaWJyYXJ5KHJ3b3JsZG1hcCkNCm1hcCA8LSBnZXRNYXAocmVzb2x1dGlvbiA9ICJsb3ciKSAjY3JlYXRlcyBhbiBvYmplY3QgY2FsbGVkIG1hcCBhdCBsb3cgcmVzb3VsdGlvbg0KcGxvdChtYXAsIHhsaW0gPSBjKC0xODAsIC00NCksIHlsaW0gPWMoMCw4MCksIGFzcCA9IDEpICN0aGUgeCBhbmQgeSBsaW0gYXJlIHRoZSBsb25nLWxhdCBib3VuZHMgb2YgdGhlIG1hcA0KcG9pbnRzKHRpZHlkYXRhJGRlY2ltYWxMb25naXR1ZGUsIHRpZHlkYXRhJGRlY2ltYWxMYXRpdHVkZSkgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmBgYA0Kbm93IGV4dHJhY3QganVzdCB0aGUgQXRsYW50aWMgQ2FuYWRhIGRhdGEuDQpUaGUgbG9uLWxhdCBzdHVkeSBhcmVhICh3aGljaCBjYXB0dXJlcyB0aGUgd2hvbGUgQXRsYW50aWMgQ2FuYWRpYW4gRUVaIHVwIHRvIHRoZSBub3J0aCBvZiBSZXNvbHV0aW9uIElzbGFuZCBpbiB0aGUgSHVkc29uIFN0cmFpdC8gRGF2aXMgU3RyYWl0KSBpcyAtNzEuMCwtNDMuMCw2Mi4wLDM4LjAgDQpgYGB7ciBtYXAgb25seSBhdGxhbnRpYyBjYW5hZGlhbiBvY2N1cnJlbmNlc30NCnRpZHlkYXRhIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGRlY2ltYWxMb25naXR1ZGUgPiAtNzEsIF0NCnRpZHlkYXRhIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGRlY2ltYWxMb25naXR1ZGUgPCAtNDMsIF0NCnRpZHlkYXRhIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGRlY2ltYWxMYXRpdHVkZSA+IDM4LCBdDQpwbG90KG1hcCwgeGxpbSA9IGMoLTE4MCwgLTQ0KSwgeWxpbSA9YygwLDgwKSwgYXNwID0gMSkgDQpwb2ludHModGlkeWRhdGEkZGVjaW1hbExvbmdpdHVkZSwgdGlkeWRhdGEkZGVjaW1hbExhdGl0dWRlKQ0KYGBgDQpvayBsb29rcyBnb29kLi4uc2F2ZSB3aGF0IHlvdSBoYXZlIHNvIGZhciB0byBhIC5jc3YNCmBgYHtyIHNhdmUgdGlkeWRhdGEgdG8gY3N2fQ0Kd3JpdGUuY3N2KHRpZHlkYXRhLCBmaWxlID0gIi4uL2RhdGEvYmlvL2NhcGVsaW5fb2Jpc190aWR5LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiMgQ29sdW1uIHJlbW92YWwNClNvIHRoZXJlIGFyZSBtYW55IGNvbHVtbnMgdGhhdCB5b3UgZG9uJ3QgbmVlZC4uIHlvdSB3YW50IHRvIGtlZXANCmlkDQpkZWNpbWFsTGF0aXR1ZGUNCmRlY2ltYWxMb25naXR1ZGUNCmRhdGVjb2xsZWN0ZWQNCmluc3RpdHV0aW9uY29kZQ0KaW5kaXZpZHVhbGNvdW50DQpyZXNuYW1lDQpvcmlnaW5hbHNjaWVudGlmaWNuYW1lDQpjb2xsZWN0aW9uY29kZSAodGhpcyBjb250YWlucyBzb21lIGluZm8gdGhhdCBtaWdodCBoZWxwIHdpdGggZmluZGluZyBvdXQgZ2VhciB1c2VkIGluIHRoZSBzdXJ2ZXkpDQoNCmBgYHtyIHNlbGVjdCBjb2x1bXMgbmVlZGVkfQ0KdGlkeWRhdGEgPC0gc3Vic2V0KHRpZHlkYXRhLCBzZWxlY3QgPSBjKGlkLCBkZWNpbWFsTGF0aXR1ZGUsIGRlY2ltYWxMb25naXR1ZGUsIGRhdGVjb2xsZWN0ZWQsIGluc3RpdHV0aW9uY29kZSwgaW5kaXZpZHVhbGNvdW50LCByZXNuYW1lLCBvcmlnaW5hbHNjaWVudGlmaWNuYW1lLCBjb2xsZWN0aW9uY29kZSkpDQpoZWFkKHRpZHlkYXRhKQ0KYGBgDQoNCiMgTW9udGggeWVhciBjb2x1bW4gY3JlYXRpb24NCm1ha2UgY29sdW1ucyBmb3IgdGhlIHllYXJzIGFuZCBtb250aCBiYXNlZCBvbiB0aGUgZGF0ZWNvbGxlY3RlZCBjb2x1bW4NCmBgYHtyIG5ldyB5eW1tZGQgY29sdW1uc30NCnRpZHlkYXRhJHllYXIgPC0gZm9ybWF0KGFzLkRhdGUodGlkeWRhdGEkZGF0ZWNvbGxlY3RlZCksICIlWSIpICNjcmVhdGVkIGEgbmV3IGNvbHVtbiBjYWxsZWQgeWVhcg0KdGlkeWRhdGEkbW9udGggPC0gZm9ybWF0KGFzLkRhdGUodGlkeWRhdGEkZGF0ZWNvbGxlY3RlZCksICIlbSIpICNjcmVhdGVkIGEgbmV3IGNvbHVtbiBjYWxsZWQgbW9udGgNCnRpZHlkYXRhJGRheSA8LSBmb3JtYXQoYXMuRGF0ZSh0aWR5ZGF0YSRkYXRlY29sbGVjdGVkKSwgIiVkIikgI2NyZWF0ZWQgYSBuZXcgY29sdW1uIGNhbGxlZCBkYXkgDQpoZWFkKHRpZHlkYXRhKQ0KYGBgDQoNCnRoZSB5ZWFyLCBtb250aCwgZGF5IGNvbHVtbnMgYXJlIGNoYXJhY3RlcnMgQ2hhbmdlIHRvIG51bWVyaWMNCmBgYHtyIG5ldyB5eW1tZGQgY29sdW1ucyAyfQ0KdGlkeWRhdGEkeWVhciA8LSBhcy5udW1lcmljKHRpZHlkYXRhJHllYXIpDQp0aWR5ZGF0YSRtb250aCA8LSBhcy5udW1lcmljKHRpZHlkYXRhJG1vbnRoKQ0KdGlkeWRhdGEkZGF5IDwtIGFzLm51bWVyaWModGlkeWRhdGEkZGF5KQ0KaGVhZCh0aWR5ZGF0YSkNCmBgYA0KDQojIHJlbW92ZSBkYXRhIHdpdGhvdXQgbW9udGgveWVhciBpbmZvDQoNCmNvdW50IE5BcyBpbiB0aGUgZGF0YXNldC4gTWFpbmx5IHlvdSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgZGF0ZWNvbGxlY3RlZCBjb2x1bW4gKGlnbm9yZSBpbmRpdmlkdWFsIGNvdW50IC0geW91IGtub3cgdGhlcmUgaXMgYSBsb3QgbWlzc2luZykNCmBgYHtyfQ0KbWlzc2luZ2RhdGEgPC0gYXBwbHkodGlkeWRhdGEsIDIsIGZ1bmN0aW9uICh4KSBzdW0oaXMubmEoeCkpKQ0KbWlzc2luZ2RhdGENCmBgYA0KaG1tIGludGVyZXN0aW5nIC0geW91IGhhdmUgNzcxIGNvbHVtbnMgZnJvbSB5ZWFyIG1vbnRoIGFuZCBkYXkgd2l0aCBtaXNzaW5nIGRhdGEsIGJ1dCBkYXRhY29sbGVjdGVkIGhhcyAwLiBUaGVyZSBtYXkgYmUgYSBmb3JtYXR0aW5nIGlzc3VlLg0KVG8gdGFrZSBhIGNsb3NlciBsb29rLCBzdWJzZXQgYWxsIHJvd3Mgd2hlcmUgeWVhciA9PSBuYQ0KDQpgYGB7cn0NCm1pc3NpbmdkYXRhcm93cyA8LSB0aWR5ZGF0YVtpcy5uYSh0aWR5ZGF0YSR5ZWFyKSwgXQ0KaGVhZChtaXNzaW5nZGF0YXJvd3MpDQpgYGANCnNvIHRoZSBOQXMgaW4gdGhlIHllYXIgY29sdW1uIHJlbGF0ZSB0byBubyBkYXRhICh3aXRob3V0IGEgbmEgdmFsdWUgYXR0YWNoZWQpLiBSZW1vdmUgYWxsIHJvd3Mgd2hlcmUgeWVhciA9PSBuYQ0KYGBge3J9DQp0aWR5ZGF0YSA8LSB0aWR5ZGF0YVshaXMubmEodGlkeWRhdGEkeWVhciksIF0NCm1pc3NpbmdkYXRhMiA8LSBhcHBseSh0aWR5ZGF0YSwgMiwgZnVuY3Rpb24gKHgpIHN1bShpcy5uYSh4KSkpDQptaXNzaW5nZGF0YTINCmBgYA0KDQoNCiMgUmVtb3ZlIGFueSBkdXBsaWNhdGUgZW50cmllcw0KVGhlIGRwbHlyIHBhY2thZ2UncyBkaXN0aW5jdCBmdW5jdGlvbiByZW1vdmVzIGFueSBkdXBsaWNhdGUgcm93cyAoYmFzZWQgb24gYWxsIGNvbHVtbnMgRVhDRVBUIGlkIGFzIHRoaXMgaXMgYWx3YXlzIGdvaW5nIHRvIGJlIHVuaXF1ZSwgYW5kIHllYXIgbW9udGggZGF5IGFzIHRoaXMgaXMgZ2VuZXJhdGVkIGZyb20gZGF0ZWNvbGxlY3RlZCkNCg0KYGBge3J9DQpsaWJyYXJ5KCJkcGx5ciIpDQp0aWR5ZGF0YSA8LSBkaXN0aW5jdCh0aWR5ZGF0YSwgZGVjaW1hbExhdGl0dWRlLCBkZWNpbWFsTG9uZ2l0dWRlLCBkYXRlY29sbGVjdGVkLCBpbnN0aXR1dGlvbmNvZGUsIGluc3RpdHV0aW9uY29kZSwgaW5kaXZpZHVhbGNvdW50LCByZXNuYW1lLCBvcmlnaW5hbHNjaWVudGlmaWNuYW1lLCAua2VlcF9hbGwgPSBUKSAjdGhlIC5rZWVwX2FsbCBtZWFucyB0aGF0IGlkIGlzbid0IGV4Y2x1ZGVkIGZyb20gdGhlIG91dHB1dA0KaGVhZCh0aWR5ZGF0YSkNCmBgYA0KDQoNCiMgSW5zdGl0dXRpb25zDQpMZXRzIHRha2UgYSBsb29rIGF0IHRoZSBpbnN0aXR1dGlvbmNvZGUgdG8gbWFrZSBzdXJlIHRoZSBuYW1lcyBtYWtlIHNlbnNlLi4uDQpgYGB7cn0NCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSBhcy5jaGFyYWN0ZXIodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlKQ0Kd2hvc2FtcGxlZCA8LSB1bmlxdWUodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCndob3NhbXBsZWRvcmRlcmVkIDwtIHNvcnQod2hvc2FtcGxlZCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCndob3NhbXBsZWRvcmRlcmVkDQpgYGANCk9rIHNvIGEgbnVtYmVyIG9mIHRoZXNlIG5hbWVzIGFjdHVhbGx5IHJlcHJlc2VudCB0aGUgc2FtZSBpbnNpdGl1dGlvbiAoZS5nLiBbREZPIFJlZ2lvbnNdKGh0dHA6Ly93d3cuZGZvLW1wby5nYy5jYS9yZWdpb25zL2luZGV4LWVuZy5odG0pLiBTb21lIGRldGFpbHMgW2hlcmVdKGZ0cDovL2Z0cC5hb21sLm5vYWEuZ292L29kL3B1Yi9saWJyYXJ5L21ldGhvZHMtYnJhbnRvbi5wZGYpIGFuZCB0aGUgZmlyc3QgaXMgbm8gaW5zdGl0dXRpb24gKHlvdSBtaWdodCBiZSBhYmxlIHRvIGZpZ3VyZSBpdCBvdXQgdGhvdWdoKS4gDQpUaGUgbWVyZ2VzIG5lZWRlZCBhcmUgYXMgZm9sbG93cw0KIkJlZGZvcmQgSW5zdGl0dXRlIG9mIE9jZWFub2dyYXBoeSAoQklPKSIgJiAiQklPIiAmICJERk8tU0YiID09IERGT01UTVMgDQoiREZPLUlNTCIgJiAiSU1MLU1MSSIgJiAiSU1MX01MSSIgJiAiREZPLU5HIiA9PSBERk9RQyANCiJERk8tTkZMRCIgJiAiTm9ydGggQXRsYW50aWMgRmlzaGVyaWVzIENlbnRyZSIgPT0gIkRGT05MIiANCiJOTUZTLU5FRlNDIiAmICJOT0FBLCBOTUZTLCBOb3J0aGVhc3QgRmlzaGVyaWVzIFNjaWVuY2UgQ2VudGVyIiA9PSBORUZTQw0KIlRoZSBBdGxhbnRpYyByZWZlcmVuY2UgQ2VudHJlIiAmICJUaGUgQXRsYW50aWMgUmVmZXJlbmNlIENlbnRyZSAoQVJDKSIgPT0gQVJDIA0KIkRGTy1TRyIgJiAiREZPIEd1bGYgRmlzaGVyaWVzIENlbnRyZSIgPT0gREZPR1VMRg0KDQphbmQgc29tZSB5b3UgY2FuIGp1c3QgbWFrZSBzaG9ydGVyDQoiTm9ydGh3ZXN0IEF0bGFudGljIEZpc2hlcmllcyBPcmdhbml6YXRpb24gKE5BRk8pIiA9PSBOQUZPDQoiREZPLUlTRE0iID09IERGT0lTRE0NCiJNYWluZSBETVIiID09IE1haW5lRE1SDQpgYGB7ciBjb25zaXN0ZW50IGluc3RpdHV0aW9uY29kZXN9DQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiQmVkZm9yZCBJbnN0aXR1dGUgb2YgT2NlYW5vZ3JhcGh5IChCSU8pIiwgIkRGT01UTVMiKQ0KdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlIDwtIHJlcGxhY2UodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlLCB0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIkJJTyIsICJERk9NVE1TIikNCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSByZXBsYWNlKHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSwgdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJERk8tU0YiLCAiREZPTVRNUyIpDQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPLUlNTCIsICJERk9RQyIpDQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiSU1MLU1MSSIsICJERk9RQyIpDQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPLU5HIiwgIkRGT1FDIikgIA0KdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlIDwtIHJlcGxhY2UodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlLCB0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIklNTF9NTEkiLCAiREZPUUMiKQ0KdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlIDwtIHJlcGxhY2UodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlLCB0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIkRGTy1ORkxEIiwgIkRGT05MIikNCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSByZXBsYWNlKHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSwgdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJOb3J0aCBBdGxhbnRpYyBGaXNoZXJpZXMgQ2VudHJlIiwgIkRGT05MIikNCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSByZXBsYWNlKHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSwgdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJOTUZTLU5FRlNDIiwgIk5FRlNDIikNCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSByZXBsYWNlKHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSwgdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJOT0FBLCBOTUZTLCBOb3J0aGVhc3QgRmlzaGVyaWVzIFNjaWVuY2UgQ2VudGVyIiwgIk5FRlNDIikNCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSByZXBsYWNlKHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSwgdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJUaGUgQXRsYW50aWMgUmVmZXJlbmNlIENlbnRyZSAoQVJDKSIsICJBUkMiKQ0KdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlIDwtIHJlcGxhY2UodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlLCB0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIlRoZSBBdGxhbnRpYyByZWZlcmVuY2UgQ2VudHJlIiwgIkFSQyIpDQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPLVNHIiwgIkRGT0d1bGYiKQ0KdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlIDwtIHJlcGxhY2UodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlLCB0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIkRGTyBHdWxmIEZpc2hlcmllcyBDZW50cmUiLCAiREZPR3VsZiIpDQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiTm9ydGh3ZXN0IEF0bGFudGljIEZpc2hlcmllcyBPcmdhbml6YXRpb24gKE5BRk8pIiwgIk5BRk8iKQ0KdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlIDwtIHJlcGxhY2UodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlLCB0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIkRGTy1DZW50cmFsIGFuZCBBcmN0aWMsIEZyZXNod2F0ZXIgSW5zdGl0dXRlIChGV0kpIiwgIkRGT0NFTkFSQyIpDQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPLUlTRE0iLCAiREZPSVNETSIpDQp0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPC0gcmVwbGFjZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUsIHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiTWFpbmUgRE1SIiwgIk1haW5lRE1SIikNCg0KI3JlY2hlY2sNCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSBhcy5jaGFyYWN0ZXIodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlKQ0Kd2hvc2FtcGxlZCA8LSB1bmlxdWUodGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCndob3NhbXBsZWRvcmRlcmVkIDwtIHNvcnQod2hvc2FtcGxlZCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCndob3NhbXBsZWRvcmRlcmVkDQpgYGANCg0KTm93IGxvb2sgYXQgdGhlIG1pc3NpbmcgaW5zdGl0dXRpb24uIFVzZSByZXNuYW1lIHRvIHNlZSBpZiBpdCBoZWxwcy4uLg0KYGBge3IgY2hlY2sgbWlzc2luZyBpbnN0aXR1dGlvbmNvZGV9DQptaXNzaW5naW5zdCA8LSBzdWJzZXQodGlkeWRhdGEsIGluc3RpdHV0aW9uY29kZSA9PSAiIikNCm1pc3NpbmdpbnN0DQpgYGANCm9rIG5vdyBjaGVjayBmb3IgdW5pcXVlIHJlc25hbWUuLi4NCmBgYHtyIElEIG1pc3NpbmcgaW5zdGl0dXRpb25jb2RlfQ0KbWlzc2luZ2luc3QkcmVzbmFtZSA8LSBhcy5jaGFyYWN0ZXIobWlzc2luZ2luc3QkcmVzbmFtZSkNCm1pc3NpbmdpbnN0dW5pcXVlIDwtIHVuaXF1ZShtaXNzaW5naW5zdCRyZXNuYW1lKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCm1pc3NpbmdpbnN0dW5pcXVlZG9yZGVyZWQgPC0gc29ydChtaXNzaW5naW5zdHVuaXF1ZSkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCm1pc3NpbmdpbnN0dW5pcXVlZG9yZGVyZWQgPC0gYXMuY2hhcmFjdGVyKG1pc3NpbmdpbnN0dW5pcXVlZG9yZGVyZWQpDQptaXNzaW5naW5zdHVuaXF1ZWRvcmRlcmVkDQpgYGANCg0KT2sgc29vIGxvb2tpbmcgYXQgdGhlIFtPQklTIG1ldGFkYXRhXShodHRwOi8vd3d3LmlvYmlzLm9yZy9leHBsb3JlLyMvZGF0YXNldC80MzU2KSwgdGhlIGluc3RpdHV0aW9uIGlzIHRoZSBDb25zZXJ2YXRpb24gb2YgQXJjdGljIEZsb3JhIGFuZCBGYXVuYSAoQ0FGRikNCmBgYHtyIGZpeCBtaXNzaW5nIGluc3RpdHV0aW9uY29kZX0NCnRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA8LSByZXBsYWNlKHRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSwgdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICIiLCAiQ0FGRiIpDQp3aG9zYW1wbGVkIDwtIHVuaXF1ZSh0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUpICNtYWtlcyBhIHZhcmlhYmxlIG9mIGluc3RpdHV0aW9ucw0Kd2hvc2FtcGxlZG9yZGVyZWQgPC0gc29ydCh3aG9zYW1wbGVkKSAjanVzdCBwdXRzIHRoZSBsaXN0IGluIA0Kd2hvc2FtcGxlZG9yZGVyZWQNCmBgYA0KDQpOb3cgbGV0cyBjaGVjayB0aGUgbnVtYmVyIG9mIHJlY29yZHMgYW5kIHNwYXRpYWwtdGVtcG9yYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBvYnNlcnZhdGlvbnMgYnkgaW5zdGl0dXRpb24gY29kZSB0byBtYWtlIHN1cmUgbm9uZSBhcmUgZG9kZ3kNCg0KZmlyc3QgYSB0YWJsZSBvZiBob3cgbWFueSBvYnNlcnZhdGlvbnMgZWFjaCBpbnN0aXR1aW9uY29kZSBoYXMNCmBgYHtyIGluc3RpdHV0aW9uIGNvZGUgYW5hbHlzaXMgLSBjb3VudH0NCmxpYnJhcnkocGx5cikgI3RvIHVzZSB0aGUgY291bnQgZnVuY3Rpb24NCm9ic19ieV9pbnMgPC0gY291bnQodGlkeWRhdGEsICJpbnN0aXR1dGlvbmNvZGUiKQ0Kb2JzX2J5X2lucw0Kd3JpdGUuY3N2KG9ic19ieV9pbnMsIGZpbGUgPSAiLi4vb3V0cHV0L2Jpby9ub19vYnNlcnZhdGlvbnNfaW5zdGl0dXRpb25jb2RlLmNzdiIpDQpgYGANCm9rIHNvIElNUiwgTkFGTywgSUNFUywgJiBVU00gaGF2ZSB2ZXJ5IGZldyBlbnRyaWVzICgxLCAxLCAxLCBhbmQgMyByZXNwZWN0aXZlbHkpDQoNCkxldHMgdGFrZSBhIGxvb2sgYXQgdGhlIHNwYXRpYWwgYnJlYWtkb3duIG9mIHRoZXNlIGluc3RpdHV0aW9ucy5GaXJzdCBhbGwgcG9pbnRzLi4uDQoNCmBgYHtyfQ0KbWFwMiA8LSBnZXRNYXAocmVzb2x1dGlvbiA9ICJsb3ciKSAjY3JlYXRlcyBhbiBvYmplY3QgY2FsbGVkIG1hcCBhdCBsb3cgcmVzb3VsdGlvbg0KcGxvdChtYXAyLCB4bGltID0gYygtNzEsIC00MyksIHlsaW0gPWMoMzgsIDYyKSwgYXNwID0gMSwgbWFpbiA9ICJBbGwgT2NjdXJyZW5jZXMiLCBjb2wgPSAiY29ybnNpbGsiKSAjdGhlIHggYW5kIHkgbGltIGFyZSB0aGUgbG9uZy1sYXQgYm91bmRzIG9mIHRoZSBtYXANCnBvaW50cyh0aWR5ZGF0YSRkZWNpbWFsTG9uZ2l0dWRlLCB0aWR5ZGF0YSRkZWNpbWFsTGF0aXR1ZGUsIGNvbCA9ICJyZWQiKSAjdGhpcyBhZGRzIHBvaW50cyB0byB0aGUgbWFwZXQiLCB4bGFiID0gIkxvbmdpdHVkZSIsIHlsYWIgPSAiTGF0aXR1ZGUiKQ0KZGV2LmNvcHkocG5nLCAiLi4vb3V0cHV0L2Jpby9hbGxfb2NjdXJyZW5jZXMucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQpgYGANCk5vdGUgdGhlcmUgaXMgb25lIHBvaW50IHVwIGJ5IGljZWxhbmQgdGhhdCB5b3Ugc2hvdWxkIGdldCByaWQgb2YgKEljZWxhbmRpYyBwb3B1bGF0aW9uIHRob3VnaHQgdG8gYmUgc2VwZXJhdGUgZnJvbSBMYWJyYWRvciwgYnV0IGl0IGlzIHVuY2xlYXIgaWYgdGhpcyBpcyB0cnVlIG9yIG5vdCkuDQoNCk1hcCB0aGUgaW5zdGl0dXRpb25jb2RlID09IEFSQyBvbmx5IGRhdGEuLi4NCmBgYHtyIG1hcCBvYnMgYnkgaW5zdGl0dXR1aW9ufQ0KQVJDX29icyA8LSB0aWR5ZGF0YVt0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIkFSQyIsIF0NCm1hcDIgPC0gZ2V0TWFwKHJlc29sdXRpb24gPSAibG93IikgI2NyZWF0ZXMgYW4gb2JqZWN0IGNhbGxlZCBtYXAgYXQgbG93IHJlc291bHRpb24NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiQXJjIE9jY3VycmVuY2VzIiwgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoQVJDX29icyRkZWNpbWFsTG9uZ2l0dWRlLCBBUkNfb2JzJGRlY2ltYWxMYXRpdHVkZSwgY29sID0gInJlZCIpICN0aGlzIGFkZHMgcG9pbnRzIHRvIHRoZSBtYXBldCIsIHhsYWIgPSAiTG9uZ2l0dWRlIiwgeWxhYiA9ICJMYXRpdHVkZSIpDQpkZXYuY29weShwbmcsICIuLi9vdXRwdXQvYmlvL0FSQ19vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQoNCkNBRkZfb2JzIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiQ0FGRiIsIF0NCm1hcDIgPC0gZ2V0TWFwKHJlc29sdXRpb24gPSAibG93IikgI2NyZWF0ZXMgYW4gb2JqZWN0IGNhbGxlZCBtYXAgYXQgbG93IHJlc291bHRpb24NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiQ0FGRiBPY2N1cnJlbmNlcyIsICBjb2wgPSAiY29ybnNpbGsiKSAjdGhlIHggYW5kIHkgbGltIGFyZSB0aGUgbG9uZy1sYXQgYm91bmRzIG9mIHRoZSBtYXANCnBvaW50cyhDQUZGX29icyRkZWNpbWFsTG9uZ2l0dWRlLCBDQUZGX29icyRkZWNpbWFsTGF0aXR1ZGUsIGNvbCA9ICJyZWQiKSAjdGhpcyBhZGRzIHBvaW50cyB0byB0aGUgbWFwZXQiLCB4bGFiID0gIkxvbmdpdHVkZSIsIHlsYWIgPSAiTGF0aXR1ZGUiKQ0KZGV2LmNvcHkocG5nLCAiLi4vb3V0cHV0L2Jpby9DQUZGX29jY3VycmVuY2VzX2FsbC5wbmciKSAjdGhpcyBwcmludHMgYSBwbmcgb2YgdGhlIHBsb3QNCmRldi5vZmYoKSAjdGhpcyB0dXJucyBvZmYgdGhlIHByaW50IGNvbW1hbmQNCg0KREZPQ0VOQVJDX29icyA8LSB0aWR5ZGF0YVt0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIkRGT0NFTkFSQyIsIF0NCm1hcDIgPC0gZ2V0TWFwKHJlc29sdXRpb24gPSAibG93IikgI2NyZWF0ZXMgYW4gb2JqZWN0IGNhbGxlZCBtYXAgYXQgbG93IHJlc291bHRpb24NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiREZPIENlbnRyYWwgJiBBcmN0aWMgT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoREZPQ0VOQVJDX29icyRkZWNpbWFsTG9uZ2l0dWRlLCBERk9DRU5BUkNfb2JzJGRlY2ltYWxMYXRpdHVkZSwgY29sID0gInJlZCIpICN0aGlzIGFkZHMgcG9pbnRzIHRvIHRoZSBtYXBldCIsIHhsYWIgPSAiTG9uZ2l0dWRlIiwgeWxhYiA9ICJMYXRpdHVkZSIpDQpkZXYuY29weShwbmcsICIuLi9vdXRwdXQvYmlvL0RGT0NFTkFSQ19vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQoNCkRGT0d1bGZfb2JzIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPR3VsZiIsIF0NCm1hcDIgPC0gZ2V0TWFwKHJlc29sdXRpb24gPSAibG93IikgI2NyZWF0ZXMgYW4gb2JqZWN0IGNhbGxlZCBtYXAgYXQgbG93IHJlc291bHRpb24NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiREZPIEd1bGYgT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoREZPR3VsZl9vYnMkZGVjaW1hbExvbmdpdHVkZSwgREZPR3VsZl9vYnMkZGVjaW1hbExhdGl0dWRlLCBjb2wgPSAicmVkIikgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmRldi5jb3B5KHBuZywgIi4uL291dHB1dC9iaW8vREZPR3VsZl9vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQoNCkRGT0lTRE1fb2JzIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPSVNETSIsIF0NCm1hcDIgPC0gZ2V0TWFwKHJlc29sdXRpb24gPSAibG93IikgI2NyZWF0ZXMgYW4gb2JqZWN0IGNhbGxlZCBtYXAgYXQgbG93IHJlc291bHRpb24NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiREZPIElTRE0gT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoREZPSVNETV9vYnMkZGVjaW1hbExvbmdpdHVkZSwgREZPSVNETV9vYnMkZGVjaW1hbExhdGl0dWRlLCBjb2wgPSAicmVkIikgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmRldi5jb3B5KHBuZywgIi4uL291dHB1dC9iaW8vREZPSVNETV9vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQoNCkRGT01UTVNfb2JzIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPTVRNUyIsIF0NCm1hcDIgPC0gZ2V0TWFwKHJlc29sdXRpb24gPSAibG93IikgI2NyZWF0ZXMgYW4gb2JqZWN0IGNhbGxlZCBtYXAgYXQgbG93IHJlc291bHRpb24NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiREZPIE1hcml0aW1lcyBPY2N1cnJlbmNlcyIsICBjb2wgPSAiY29ybnNpbGsiKSAjdGhlIHggYW5kIHkgbGltIGFyZSB0aGUgbG9uZy1sYXQgYm91bmRzIG9mIHRoZSBtYXANCnBvaW50cyhERk9NVE1TX29icyRkZWNpbWFsTG9uZ2l0dWRlLCBERk9NVE1TX29icyRkZWNpbWFsTGF0aXR1ZGUsIGNvbCA9ICJyZWQiKSAjdGhpcyBhZGRzIHBvaW50cyB0byB0aGUgbWFwZXQiLCB4bGFiID0gIkxvbmdpdHVkZSIsIHlsYWIgPSAiTGF0aXR1ZGUiKQ0KZGV2LmNvcHkocG5nLCAiLi4vb3V0cHV0L2Jpby9ERk9NVE1TX29jY3VycmVuY2VzX2FsbC5wbmciKSAjdGhpcyBwcmludHMgYSBwbmcgb2YgdGhlIHBsb3QNCmRldi5vZmYoKSAjdGhpcyB0dXJucyBvZmYgdGhlIHByaW50IGNvbW1hbmQNCg0KREZPTkxfb2JzIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiREZPTkwiLCBdDQptYXAyIDwtIGdldE1hcChyZXNvbHV0aW9uID0gImxvdyIpICNjcmVhdGVzIGFuIG9iamVjdCBjYWxsZWQgbWFwIGF0IGxvdyByZXNvdWx0aW9uDQpwbG90KG1hcDIsIHhsaW0gPSBjKC03MSwgLTQzKSwgeWxpbSA9YygzOSwgNjIpLCBhc3AgPSAxLCBtYWluID0gIkRGTyBOZXdmb3V1bmRsYW5kICYgTGFicmFkb3IgT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoREZPTkxfb2JzJGRlY2ltYWxMb25naXR1ZGUsIERGT05MX29icyRkZWNpbWFsTGF0aXR1ZGUsIGNvbCA9ICJyZWQiKSAjdGhpcyBhZGRzIHBvaW50cyB0byB0aGUgbWFwZXQiLCB4bGFiID0gIkxvbmdpdHVkZSIsIHlsYWIgPSAiTGF0aXR1ZGUiKQ0KZGV2LmNvcHkocG5nLCAiLi4vb3V0cHV0L2Jpby9ERk9OTF9vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQoNCkRGT1FDX29icyA8LSB0aWR5ZGF0YVt0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIkRGT1FDIiwgXQ0KbWFwMiA8LSBnZXRNYXAocmVzb2x1dGlvbiA9ICJsb3ciKSAjY3JlYXRlcyBhbiBvYmplY3QgY2FsbGVkIG1hcCBhdCBsb3cgcmVzb3VsdGlvbg0KcGxvdChtYXAyLCB4bGltID0gYygtNzEsIC00MyksIHlsaW0gPWMoMzksIDYyKSwgYXNwID0gMSwgbWFpbiA9ICJERk8gUXVlYmVjIE9jY3VycmVuY2VzIiwgIGNvbCA9ICJjb3Juc2lsayIpICN0aGUgeCBhbmQgeSBsaW0gYXJlIHRoZSBsb25nLWxhdCBib3VuZHMgb2YgdGhlIG1hcA0KcG9pbnRzKERGT1FDX29icyRkZWNpbWFsTG9uZ2l0dWRlLCBERk9RQ19vYnMkZGVjaW1hbExhdGl0dWRlLCBjb2wgPSAicmVkIikgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmRldi5jb3B5KHBuZywgIi4uL291dHB1dC9iaW8vREZPUUNfb2NjdXJyZW5jZXNfYWxsLnBuZyIpICN0aGlzIHByaW50cyBhIHBuZyBvZiB0aGUgcGxvdA0KZGV2Lm9mZigpICN0aGlzIHR1cm5zIG9mZiB0aGUgcHJpbnQgY29tbWFuZA0KDQpJQ0VTX29icyA8LSB0aWR5ZGF0YVt0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIklDRVMiLCBdDQptYXAyIDwtIGdldE1hcChyZXNvbHV0aW9uID0gImxvdyIpICNjcmVhdGVzIGFuIG9iamVjdCBjYWxsZWQgbWFwIGF0IGxvdyByZXNvdWx0aW9uDQpwbG90KG1hcDIsIHhsaW0gPSBjKC03MSwgLTQzKSwgeWxpbSA9YygzOSwgNjIpLCBhc3AgPSAxLCBtYWluID0gIklDRVMgT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoSUNFU19vYnMkZGVjaW1hbExvbmdpdHVkZSwgSUNFU19vYnMkZGVjaW1hbExhdGl0dWRlLCBjb2wgPSAicmVkIikgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmRldi5jb3B5KHBuZywgIi4uL291dHB1dC9iaW8vSUNFU19vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQoNCklNUl9vYnMgPC0gdGlkeWRhdGFbdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJJTVIiLCBdDQptYXAyIDwtIGdldE1hcChyZXNvbHV0aW9uID0gImxvdyIpICNjcmVhdGVzIGFuIG9iamVjdCBjYWxsZWQgbWFwIGF0IGxvdyByZXNvdWx0aW9uDQpwbG90KG1hcDIsIHhsaW0gPSBjKC03MSwgLTQzKSwgeWxpbSA9YygzOSwgNjIpLCBhc3AgPSAxLCBtYWluID0gIklNUiBPY2N1cnJlbmNlcyIsICBjb2wgPSAiY29ybnNpbGsiKSAjdGhlIHggYW5kIHkgbGltIGFyZSB0aGUgbG9uZy1sYXQgYm91bmRzIG9mIHRoZSBtYXANCnBvaW50cyhJTVJfb2JzJGRlY2ltYWxMb25naXR1ZGUsIElNUl9vYnMkZGVjaW1hbExhdGl0dWRlLCBjb2wgPSAicmVkIikgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmRldi5jb3B5KHBuZywgIi4uL291dHB1dC9iaW8vSU1SX29jY3VycmVuY2VzX2FsbC5wbmciKSAjdGhpcyBwcmludHMgYSBwbmcgb2YgdGhlIHBsb3QNCmRldi5vZmYoKSAjdGhpcyB0dXJucyBvZmYgdGhlIHByaW50IGNvbW1hbmQNCg0KTWFpbmVETVJfb2JzIDwtIHRpZHlkYXRhW3RpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiTWFpbmVETVIiLCBdDQptYXAyIDwtIGdldE1hcChyZXNvbHV0aW9uID0gImxvdyIpICNjcmVhdGVzIGFuIG9iamVjdCBjYWxsZWQgbWFwIGF0IGxvdyByZXNvdWx0aW9uDQpwbG90KG1hcDIsIHhsaW0gPSBjKC03MSwgLTQzKSwgeWxpbSA9YygzOSwgNjIpLCBhc3AgPSAxLCBtYWluID0gIk1haW5lIERNUiBPY2N1cnJlbmNlcyIsICBjb2wgPSAiY29ybnNpbGsiKSAjdGhlIHggYW5kIHkgbGltIGFyZSB0aGUgbG9uZy1sYXQgYm91bmRzIG9mIHRoZSBtYXANCnBvaW50cyhNYWluZURNUl9vYnMkZGVjaW1hbExvbmdpdHVkZSwgTWFpbmVETVJfb2JzJGRlY2ltYWxMYXRpdHVkZSwgY29sID0gInJlZCIpICN0aGlzIGFkZHMgcG9pbnRzIHRvIHRoZSBtYXBldCIsIHhsYWIgPSAiTG9uZ2l0dWRlIiwgeWxhYiA9ICJMYXRpdHVkZSIpDQpkZXYuY29weShwbmcsICIuLi9vdXRwdXQvYmlvL01haW5lRE1SX29jY3VycmVuY2VzX2FsbC5wbmciKSAjdGhpcyBwcmludHMgYSBwbmcgb2YgdGhlIHBsb3QNCmRldi5vZmYoKSAjdGhpcyB0dXJucyBvZmYgdGhlIHByaW50IGNvbW1hbmQNCg0KTkFGT19vYnMgPC0gdGlkeWRhdGFbdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJOQUZPIiwgXQ0KbWFwMiA8LSBnZXRNYXAocmVzb2x1dGlvbiA9ICJsb3ciKSAjY3JlYXRlcyBhbiBvYmplY3QgY2FsbGVkIG1hcCBhdCBsb3cgcmVzb3VsdGlvbg0KcGxvdChtYXAyLCB4bGltID0gYygtNzEsIC00MyksIHlsaW0gPWMoMzksIDYyKSwgYXNwID0gMSwgbWFpbiA9ICJOQUZPIE9jY3VycmVuY2VzIiwgIGNvbCA9ICJjb3Juc2lsayIpICN0aGUgeCBhbmQgeSBsaW0gYXJlIHRoZSBsb25nLWxhdCBib3VuZHMgb2YgdGhlIG1hcA0KcG9pbnRzKE5BRk9fb2JzJGRlY2ltYWxMb25naXR1ZGUsIE5BRk9fb2JzJGRlY2ltYWxMYXRpdHVkZSwgY29sID0gInJlZCIpICN0aGlzIGFkZHMgcG9pbnRzIHRvIHRoZSBtYXBldCIsIHhsYWIgPSAiTG9uZ2l0dWRlIiwgeWxhYiA9ICJMYXRpdHVkZSIpDQpkZXYuY29weShwbmcsICIuLi9vdXRwdXQvYmlvL05BRk9fb2NjdXJyZW5jZXNfYWxsLnBuZyIpICN0aGlzIHByaW50cyBhIHBuZyBvZiB0aGUgcGxvdA0KZGV2Lm9mZigpICN0aGlzIHR1cm5zIG9mZiB0aGUgcHJpbnQgY29tbWFuZA0KDQpORUZTQ19vYnMgPC0gdGlkeWRhdGFbdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJORUZTQyIsIF0NCm1hcDIgPC0gZ2V0TWFwKHJlc29sdXRpb24gPSAibG93IikgI2NyZWF0ZXMgYW4gb2JqZWN0IGNhbGxlZCBtYXAgYXQgbG93IHJlc291bHRpb24NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiTkVGU0MgT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoTkVGU0Nfb2JzJGRlY2ltYWxMb25naXR1ZGUsIE5FRlNDX29icyRkZWNpbWFsTGF0aXR1ZGUsIGNvbCA9ICJyZWQiKSAjdGhpcyBhZGRzIHBvaW50cyB0byB0aGUgbWFwZXQiLCB4bGFiID0gIkxvbmdpdHVkZSIsIHlsYWIgPSAiTGF0aXR1ZGUiKQ0KZGV2LmNvcHkocG5nLCAiLi4vb3V0cHV0L2Jpby9ORUZTQ19vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQoNClJPTV9vYnMgPC0gdGlkeWRhdGFbdGlkeWRhdGEkaW5zdGl0dXRpb25jb2RlID09ICJST00iLCBdDQptYXAyIDwtIGdldE1hcChyZXNvbHV0aW9uID0gImxvdyIpICNjcmVhdGVzIGFuIG9iamVjdCBjYWxsZWQgbWFwIGF0IGxvdyByZXNvdWx0aW9uDQpwbG90KG1hcDIsIHhsaW0gPSBjKC03MSwgLTQzKSwgeWxpbSA9YygzOSwgNjIpLCBhc3AgPSAxLCBtYWluID0gIlJveWFsIE9udGFyaW8gTXVzZXVtIE9jY3VycmVuY2VzIiwgIGNvbCA9ICJjb3Juc2lsayIpICN0aGUgeCBhbmQgeSBsaW0gYXJlIHRoZSBsb25nLWxhdCBib3VuZHMgb2YgdGhlIG1hcA0KcG9pbnRzKFJPTV9vYnMkZGVjaW1hbExvbmdpdHVkZSwgUk9NX29icyRkZWNpbWFsTGF0aXR1ZGUsIGNvbCA9ICJyZWQiKSAjdGhpcyBhZGRzIHBvaW50cyB0byB0aGUgbWFwZXQiLCB4bGFiID0gIkxvbmdpdHVkZSIsIHlsYWIgPSAiTGF0aXR1ZGUiKQ0KZGV2LmNvcHkocG5nLCAiLi4vb3V0cHV0L2Jpby9ST01fb2NjdXJyZW5jZXNfYWxsLnBuZyIpICN0aGlzIHByaW50cyBhIHBuZyBvZiB0aGUgcGxvdA0KZGV2Lm9mZigpICN0aGlzIHR1cm5zIG9mZiB0aGUgcHJpbnQgY29tbWFuZA0KDQpVU05NX29icyA8LSB0aWR5ZGF0YVt0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIlVTTk0iLCBdDQptYXAyIDwtIGdldE1hcChyZXNvbHV0aW9uID0gImxvdyIpICNjcmVhdGVzIGFuIG9iamVjdCBjYWxsZWQgbWFwIGF0IGxvdyByZXNvdWx0aW9uDQpwbG90KG1hcDIsIHhsaW0gPSBjKC03MSwgLTQzKSwgeWxpbSA9YygzOSwgNjIpLCBhc3AgPSAxLCBtYWluID0gIk5hdGlvbmFsIE11c2V1bSBvZiBOYXR1cmFsIEhpc3RvcnkgT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoVVNOTV9vYnMkZGVjaW1hbExvbmdpdHVkZSwgVVNOTV9vYnMkZGVjaW1hbExhdGl0dWRlLCBjb2wgPSAicmVkIikgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmRldi5jb3B5KHBuZywgIi4uL291dHB1dC9iaW8vVVNOTV9vY2N1cnJlbmNlc19hbGwucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQpgYGANCg0KDQpMb29raW5nIGF0IHRoZSBtYXBzLCB0aGUgUk9NLCBOQUZPLCBJTVIsIElDRVMgaGF2ZSBkYXRhIG5leHQgdG8gaWNlbGFuZC4NClNpbmNlIE5BRk8sIElNUiwgYW5kIElDRVMgb25seSBoYXZlIG9uZSBkYXRhIHBvaW50IGVhY2gsIHlvdSBjYW4gcmVtb3ZlIHRoZXNlIG9ic2VydmF0aW9ucyBlYXNpbHkgZnJvbSB0aGUgcmVjb3JkLi4uDQpgYGB7ciByZW1vdmUgaWNlbGFuZCBkYXRhfQ0KdGlkeWRhdGEgPC0gdGlkeWRhdGFbIXRpZHlkYXRhJGluc3RpdHV0aW9uY29kZSA9PSAiTkFGTyIsIF0NCnRpZHlkYXRhIDwtIHRpZHlkYXRhWyF0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIklNUiIsIF0NCnRpZHlkYXRhIDwtIHRpZHlkYXRhWyF0aWR5ZGF0YSRpbnN0aXR1dGlvbmNvZGUgPT0gIklDRVMiLCBdDQpgYGANCg0KTm93IGZvciAgUk9NIHRoZXJlIGFyZSBtb3JlIGRhdGEgcG9pbnRzLi4uDQpVc2UgaW5kZW50aWZ5IGZ1bmN0aW9uIHdoaWNoIGxldHMgeW91IGNsaWNrIG9uIGEgcG9pbnQgb24gdGhlIHBsb3QNCmBgYHtyIGxvY2F0ZSBjb29yZGluYXRlcyBvZiBpY2VsYW5kIHBvaW50fQ0KeDExKCkgI3RoaXMgb3BlbnMgdGhlIHBsb3QgaSBhIHdpbmRvdyB5b3UgY2FuIGludGVyYWN0IHdpdGgNCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM5LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiUm95YWwgT250YXJpbyBNdXNldW0gT2NjdXJyZW5jZXMiLCAgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMoUk9NX29icyRkZWNpbWFsTG9uZ2l0dWRlLCBST01fb2JzJGRlY2ltYWxMYXRpdHVkZSwgY29sID0gInJlZCIpICN0aGlzIGFkZHMgcG9pbnRzIHRvIHRoZSBtYXBldCIsIHhsYWIgPSAiTG9uZ2l0dWRlIiwgeWxhYiA9ICJMYXRpdHVkZSIpKQ0KaWRlbnRpZnkoUk9NX29icyRkZWNpbWFsTG9uZ2l0dWRlLCBST01fb2JzJGRlY2ltYWxMYXRpdHVkZSwgbGFiZWxzPVJPTV9vYnMkZGVjaW1hbExvbmdpdHVkZSkgI2RlY2ltYWxMb25naXR1ZGUgY2hvc2VuIGFzIHBsb3QgaWRlbnRpZmllciBhcyB0aGUgdmFsdWVzIGFyZSB1bmlxdWUNCmBgYA0KVGhlIHBvaW50IHRoYXQgbmVlZHMgdG8gYmUgcmVtb3ZlZCBpcyBsb2NhdGVkIGF0IC00NC45NjY2Ny4gTm90ZSB0aGlzIGlzIG5vdCB0aGUgZnVsbCB2YWx1ZSBzbyB1c2Ugc29tZSBvdGhlciBsb2NhdG9ycyB0byByZW1vdmUgdGhlIHJvdyAoeW91IGNvdWxkIGp1c3QgdXNlZCBpZCwgYnV0IHBpY2sgbXVsdGlwbGUgb3RoZXJzIGp1c3QgdG8gbGVhcm4pDQoNCmBgYHtyIHJlbW92ZSBpY2VsYW5kIHBvaW50fQ0KdGlkeWRhdGEgPC0gdGlkeWRhdGFbISh0aWR5ZGF0YSRyZXNuYW1lID09ICJGaXNoIHNwZWNpbWVucyIgJiB0aWR5ZGF0YSRkYXRlY29sbGVjdGVkID09ICIxOTY1LTA4LTEzIDEyOjAwOjAwKzAxIiksIF0NCmBgYA0KDQpub3cgcmVwbG90IGFsbCBkYXRhIGp1c3QgdG8gY2hlY2suLi4NCg0KYGBge3IgbWFwIG9jY3VycmVuY2VzIGxlc3MgaWNlbGFuZH0NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM4LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiQWxsIE9jY3VycmVuY2VzIHdpdGhvdXQgSWNlbGFuZCIsIGNvbCA9ICJjb3Juc2lsayIpICN0aGUgeCBhbmQgeSBsaW0gYXJlIHRoZSBsb25nLWxhdCBib3VuZHMgb2YgdGhlIG1hcA0KcG9pbnRzKHRpZHlkYXRhJGRlY2ltYWxMb25naXR1ZGUsIHRpZHlkYXRhJGRlY2ltYWxMYXRpdHVkZSwgY29sID0gInJlZCIpICN0aGlzIGFkZHMgcG9pbnRzIHRvIHRoZSBtYXBldCIsIHhsYWIgPSAiTG9uZ2l0dWRlIiwgeWxhYiA9ICJMYXRpdHVkZSIpDQpkZXYuY29weShwbmcsICIuLi9vdXRwdXQvYmlvL2FsbF9vY2N1cnJlbmNlc19sZXNzX2ljZWxhbmQucG5nIikgI3RoaXMgcHJpbnRzIGEgcG5nIG9mIHRoZSBwbG90DQpkZXYub2ZmKCkgI3RoaXMgdHVybnMgb2ZmIHRoZSBwcmludCBjb21tYW5kDQpgYGANCmdyZWF0ISB3cml0ZSB3aGF0IHlvdSBoYXZlIHNvIGZhciB0byBhIGNzdg0KYGBge3J9DQp3cml0ZS5jc3YodGlkeWRhdGEsIGZpbGUgPSAiLi4vZGF0YS9iaW8vY2FwZWxpbl9vYmlzX3RpZHkuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KIyBSZW1vdmUgZGF0ZXMgeW91IGRvbid0IGhhdmUgZW52aXJvbm1lbnRhbCBkYXRhIGZvcg0KVGhlIEJJT01FUiBkYXRhc2V0IHN0YXJ0cyBpbiAxOTk4LTAxIChHTE9SWVMgMTk5MyksIHNvIGN1dCBhbGwgb2NjdXJyZW5jZXMgcHJpb3IgdG8gMTk5OC0wMQ0KDQpgYGB7ciByZW1vdmUgb2NjdXJyZW5jZXMgcHJpb3IgdG8gOTgvMDF9DQp0aWR5ZGF0YSA8LSB0aWR5ZGF0YVt0aWR5ZGF0YSR5ZWFyID49IDE5OTgsIF0NCmBgYA0KDQphbmQgd3JpdGUgdG8gYSBjc3YuLi4NCmBgYHtyfQ0Kd3JpdGUuY3N2KHRpZHlkYXRhLCBmaWxlID0gIi4uL2RhdGEvYmlvL2NhcGVsaW5fb2Jpc190aWR5LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiMgQWRkaW5nIG5ldyAobm9uLWVudmlyb25tZW50YWwpIGRhdGEgdG8gdGhlIGZpbGUNClRoZXJlIGFyZSBzb21lIG1vcmUgY29sdW1ucyB5b3Ugd2FudCB0byBhZGQuLi4NCi0gT2NjdXJyZW5jZSAtIHByZXNlbmNlL2JhY2tncm91bmQgKDEvMCkNCi0gTkFGTyByZWdpb24NCi0gR2VhciB0eXBlDQotIFVuaXF1ZSBDZWxsIElEIChiYXNlZCBvbiB0aGUgZW52aXJvbm1lbnRhbCBkYXRhKQ0KDQpzbyBub3QgdG8gbWVzcyB3aXRoIHRpZHlkYXRhLCBjcmVhdGUgYSBuZXcgdmFyaWFibGUgYW5kIHdyaXRlIGEgbmV3IC5jc3YNCmBgYHtyIGNyZWF0ZSBuZXcgdmFyaWFibGUvY3N2IGZvciBhZGRpbmcgZGF0YX0NCmFkZGRhdGEgPC0gdGlkeWRhdGENCndyaXRlLmNzdihhZGRkYXRhLCBmaWxlID0gIi4uL2RhdGEvYmlvL2NhcGVsaW5fYWRkaXRpb25hbF90aWR5LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCmZpcnN0IGNyZWF0ZSBhIG5ldyBjb2x1bW4gZm9yIE9jY3VyZW5jZSwgYW5kIHBvcHVsYXRlIHdpdGggIjEiIChiZWNhdXNlIHRoZXNlIGFyZSBhbGwgcHJlc2VuY2VzKQ0KYGBge3J9DQphZGRkYXRhJG9jY3VycmVuY2UgPC0gIjEiDQpoZWFkKGFkZGRhdGEpDQpgYGANCg0KIyBBZGQgTkFGTyBSZWdpb24gb2NjdXJyZW5jZSBpcyBmcm9tDQpOQUZPIFpvbmVzIHNoYXBlZmlsZSBvYnRhaW5lZCBmcm9tIFtOQUZPXShodHRwczovL3d3dy5uYWZvLmludC9EYXRhL0dJUykNCg0KYGBge3IgTkFGTyBzaGFwZWZpbGUgZXh0cmFjdGlvbn0NCmxpYnJhcnkocmdkYWwpDQpsaWJyYXJ5KHNwKQ0KY29vcmRpbmF0ZXMoYWRkZGF0YSkgPC0gYygiZGVjaW1hbExvbmdpdHVkZSIsICJkZWNpbWFsTGF0aXR1ZGUiKSANCm5hZm9fem9uZXMgPC0gcmVhZE9HUihkc249cGF0aC5leHBhbmQoIi4uL2RhdGEvYmlvL25hZm9fem9uZXMiKSwgbGF5ZXIgPSAibmFmb196b25lc193Z3M4NCIpICN0aGlzIGxvYWRzIHRoZSBzaGFwZWZpbGUNCnByb2o0c3RyaW5nKGFkZGRhdGEpIDwtIHByb2o0c3RyaW5nKG5hZm9fem9uZXMpICN0ZWxscyBSIHRoYXQgdGhlIG9jY3VycmVuY2UgZGF0YSBpcyB0aGUgc2FtZSBwcm9qZWN0aW9uIGFzIHRoZSBzaGFwZWZpbGUNCmFkZGRhdGEkbmFmb196b25lIDwtIG92ZXIoYWRkZGF0YSwgbmFmb196b25lcykkWk9ORSAjWk9ORSBpcyB3aGVyZSB0aGUgem9uZSBkYXRhIGlzIGhlbGQgaW4gdGVoIHNoYXBlZmlsZXMnIGF0dHJpYnV0ZXMNCmhlYWQoYWRkZGF0YSkgI2p1c3QgdG8gY2hlY2sgaXQgd29ya2VkDQpgYGANCg0KR3JlYXQuIExldHMgc2VlIGlmIGFueSBhcmUgbWlzc2luZyBhIE5BRk8gWm9uZS4gQnV0IGZpcnN0LCB3cml0ZSB0byBhIGNzdiBhbmQgcmVsb2FkIGFzIHRoZSBkYXRhIGlzIG5vdyBzb21lIHdpZXJkICdzcGF0aWFsIHBvaW50cyBkYXRhZnJhbWUnLi4uDQpgYGB7cn0NCndyaXRlLmNzdihhZGRkYXRhLCAiLi4vZGF0YS9iaW8vY2FwZWxpbl9hZGRpdGlvbmFsX3RpZHkuY3N2Iiwgcm93Lm5hbWVzPUZBTFNFKQ0KYWRkZGF0YSA8LSByZWFkLmNzdigiLi4vZGF0YS9iaW8vY2FwZWxpbl9hZGRpdGlvbmFsX3RpZHkuY3N2IikNCm5hZm9fbmEgPC0gc3Vic2V0KGFkZGRhdGEsIGlzLm5hKGFkZGRhdGEkbmFmb196b25lKSkNCm5hZm9fbmENCmBgYA0KDQpVaCBvaCB0aGVyZSBpcyBhIGxvdC4gQSBiZXQgYSBidW5jaCBvZiB0aGVtIGFyZSBpbiB0aGUgSHVkc29uIFN0cmFpdCAod2hpY2ggaXMgb3V0c2lkZSB0aGUgTkFGTyBab25lKS5NYXAgdGhlIG5hZm9fbmEgcG9pbnRzLi4uDQpgYGB7cn0NCnBsb3QobWFwMiwgeGxpbSA9IGMoLTcxLCAtNDMpLCB5bGltID1jKDM4LCA2MiksIGFzcCA9IDEsIG1haW4gPSAiT2NjdXJlbmNlcyBtaXNzaW5nIGEgTkFGTyBab25lIiwgY29sID0gImNvcm5zaWxrIikgI3RoZSB4IGFuZCB5IGxpbSBhcmUgdGhlIGxvbmctbGF0IGJvdW5kcyBvZiB0aGUgbWFwDQpwb2ludHMobmFmb19uYSRkZWNpbWFsTG9uZ2l0dWRlLCBuYWZvX25hJGRlY2ltYWxMYXRpdHVkZSwgY29sID0gInJlZCIpICN0aGlzIGFkZHMgcG9pbnRzIHRvIHRoZSBtYXBldCIsIHhsYWIgPSAiTG9uZ2l0dWRlIiwgeWxhYiA9ICJMYXRpdHVkZSIpDQpgYGANCm9rIHllcyAtIEh1ZHNvbiBTdHJhaXQgaGFzIG1hbnksIGJ1dCB0aGVyZSBhcmUgc29tZSBuZWFyIHRoZSBjb2FzdCB0aGF0IGFyZSBwcm9iYWJseSBqdXN0IG1pc3NlZCBvdXQgZHVlIHRvIG1pbm9yIGRpZmZlcmVuY2VzIGluIHRoZSBwb2ludCBsb2NhdGlvbi9zaGFwZWZpbGUgYm91bmRhcmllcy4NClN0YXJ0IHdpdGggdGhlIEh1ZHNvbiBTdHJhaXQgb25lcyBhcyB0aGlzIGlzIGVhc3kgLSBhbnl0aGluZyBhYm92ZSA1Nk4sIG5hZm9fem9uZSA9PSAiSHVkc29uU3RyYWl0Ig0KDQpgYGB7cn0NCmFkZGRhdGEkbmFmb196b25lIDwtIGFzLmNoYXJhY3RlcihhZGRkYXRhJG5hZm9fem9uZSkNCmFkZGRhdGFbaXMubmEoYWRkZGF0YSldIDwtICJ4eCINCmFkZGRhdGEkbmFmb196b25lW2FkZGRhdGEkbmFmb196b25lID09ICJ4eCIgJiBhZGRkYXRhJGRlY2ltYWxMYXRpdHVkZSA+IDU2XSA8LSAiSHVkc29uU3RyYWl0Ig0KYGBgDQphbmQgbWFwIHRvIGNoZWNrDQpgYGB7cn0NCm5hZm9fbmEgPC0gc3Vic2V0KGFkZGRhdGEsIG5hZm9fem9uZSA9PSAieHgiKQ0KcGxvdChtYXAyLCB4bGltID0gYygtNzEsIC00MyksIHlsaW0gPWMoMzgsIDYyKSwgYXNwID0gMSwgbWFpbiA9ICJPY2N1cmVuY2VzIG1pc3NpbmcgYSBOQUZPIFpvbmUiLCBjb2wgPSAiY29ybnNpbGsiKSAjdGhlIHggYW5kIHkgbGltIGFyZSB0aGUgbG9uZy1sYXQgYm91bmRzIG9mIHRoZSBtYXANCnBvaW50cyhuYWZvX25hJGRlY2ltYWxMb25naXR1ZGUsIG5hZm9fbmEkZGVjaW1hbExhdGl0dWRlLCBjb2wgPSAicmVkIikgI3RoaXMgYWRkcyBwb2ludHMgdG8gdGhlIG1hcGV0IiwgeGxhYiA9ICJMb25naXR1ZGUiLCB5bGFiID0gIkxhdGl0dWRlIikNCmBgYA0Kc28gbm93IGkgbmVlZCB0byBhY2NvdW50IGZvciB0aGUgb3RoZXJzIChlaXRoZXIgYXMgb2NjdXJpbmcgb24gbGFuZCBvciBqdXN0IGluIGFuIGFyZWEgdGhhdCBpcyBtaXNzaW5nIGEgTkFGTyBab25lIHRhZykgd2hpY2ggaXMgbW9yZSB0cmlja3kuLi4gaSBtaWdodCBqdXN0IGRvIHRoaXMgYml0IGluIEFyY0dJUyBxdWlja2x5Lg0KYGBge3J9DQp3cml0ZS5jc3YoYWRkZGF0YSwgZmlsZSA9ICIuLi9kYXRhL2Jpby9jYXBlbGluX2FkZGl0aW9uYWxfdGlkeS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCmBgYA0KU28gaW4gQXJjR0lTIEkgc2F3IHRoYXQgdGhlc2UgcG9pbnRzIGZhbGwgb24gbGFuZC4gU29tZSBhcmUgZXh0cmVtZWx5IGNsb3NlIHRvIHRoZSBjb2FzdCwgc29tZSBmdXJ0aGVyIGlubGFuZC4gVGhlcmUgYXJlIG9ubHkgMTMyIG9mIHRoZXNlcG9pbnRzLCBzbyBJIHdpbGwganVzdCBkZWxldGUgdGhlbSBmcm9tIHRoZSBkYXRhYmFzZS4NCmBgYHtyfQ0KYWRkZGF0YSRuYWZvX3pvbmVbYWRkZGF0YSRuYWZvX3pvbmUgPT0gInh4Il0gPC0gTkEgI21ha2UgYWxsIHh4IHZhbHVlcyBOQQ0KYWRkZGF0YSA8LSBhZGRkYXRhWyFpcy5uYShhZGRkYXRhJG5hZm9fem9uZSksIF0NCndyaXRlLmNzdihhZGRkYXRhLCBmaWxlID0gIi4uL2RhdGEvYmlvL2NhcGVsaW5fYWRkaXRpb25hbF90aWR5LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiNHZWFyIHR5cGUNClRvIGdldCB0aGlzIGluZm9ybWF0aW9uLCBJIG5lZWQgdG8gbG9vayBhdCB0aGUgY29sbGVjdGlvbmNvZGUgZGV0YWlscyBhbmQgdGhlIE9CSVMgbWV0YWRhdGEgZm9yIGVhY2ggcmVzbmFtZSBhbmQgdGhlbiBhZGQuDQpgYGB7cn0NCmFkZGRhdGEkZ2VhciA8LSAieCIgI2NyZWF0ZSBhIG5ldyBjb2x1bW4gY2FsbGVkIGdlYXIgYW5kIHBvcHVsYXRlIHdpdGggeA0KI25vdyBnaXZlIGEgbGlzdCBvZiB0aGUgcmVzbmFtZXMuLi4NCndoaWNocmVzIDwtIHVuaXF1ZShhZGRkYXRhJHJlc25hbWUpICNtYWtlcyBhIHZhcmlhYmxlIG9mIGluc3RpdHV0aW9ucw0Kd2hpY2hyZXNvcmRlcmVkIDwtIHNvcnQod2hpY2hyZXMpICNqdXN0IHB1dHMgdGhlIGxpc3QgaW4gDQp3aGljaHJlc29yZGVyZWQNCmBgYA0KW0FyY3RpYyBTcGVjaWVzIFRyZW5kIEluZGV4IChBU1RJKSA6IE1hcmluZV0oaHR0cDovL3d3dy5pb2Jpcy5vcmcvZXhwbG9yZS8jL2RhdGFzZXQvNDM1NikuIE5vIGdlYXIgZGV0YWlscyBhdmFpbGFibGUNCmBgYHtyfQ0KYXN0aSA8LSBzdWJzZXQoYWRkZGF0YSwgcmVzbmFtZSA9PSAiQXJjdGljIFNwZWNpZXMgVHJlbmQgSW5kZXggKEFTVEkpIDogTWFyaW5lIikNCmFzdGkkY29sbGVjdGlvbmNvZGUgPC0gYXMuY2hhcmFjdGVyKGFzdGkkY29sbGVjdGlvbmNvZGUpDQphc3RpX2NvbCA8LSB1bmlxdWUoYXN0aSRjb2xsZWN0aW9uY29kZSkgI21ha2VzIGEgdmFyaWFibGUgb2YgaW5zdGl0dXRpb25zDQphc3RpX2NvbG9yZGVyZWQgPC0gc29ydChhc3RpX2NvbCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCmFzdGlfY29sb3JkZXJlZA0KYGBgDQp0aGVyZSBpcyBubyBpbmZvcm1hdGlvbiBpbiB0aGUgY29sbGVjdGlvbiBjb2RlLiBUaGUgTWV0YWRhdGEgb24gT0JJUyBhbHNvIGdpdmVzIG5vIGRldGFpbHMuIGdlYXIgPSBOQQ0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJBcmN0aWMgU3BlY2llcyBUcmVuZCBJbmRleCAoQVNUSSkgOiBNYXJpbmUiXSA8LSAiTkEiDQpgYGANCg0KW0F0bGFudGljIFJlZmVyZW5jZSBDZW50cmUgTXVzZXVtIG9mIENhbmFkaWFuIEF0bGFudGljIE9yZ2FuaXNtcyAtIEludmVydGVicmF0ZXMgYW5kIEZpc2hlcyBEYXRhXShodHRwOi8vd3d3LmlvYmlzLm9yZy9leHBsb3JlLyMvZGF0YXNldC8yOSkuDQpgYGB7cn0NCmFyY20gPC0gc3Vic2V0KGFkZGRhdGEsIHJlc25hbWUgPT0gIkF0bGFudGljIFJlZmVyZW5jZSBDZW50cmUgTXVzZXVtIG9mIENhbmFkaWFuIEF0bGFudGljIE9yZ2FuaXNtcyAtIEludmVydGVicmF0ZXMgYW5kIEZpc2hlcyBEYXRhIikNCmFyY20kY29sbGVjdGlvbmNvZGUgPC0gYXMuY2hhcmFjdGVyKGFyY20kY29sbGVjdGlvbmNvZGUpDQphcmNtX2NvbCA8LSB1bmlxdWUoYXJjbSRjb2xsZWN0aW9uY29kZSkgI21ha2VzIGEgdmFyaWFibGUgb2YgaW5zdGl0dXRpb25zDQphcmNtX2NvbG9yZGVyZWQgPC0gc29ydChhcmNtX2NvbCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCmFyY21fY29sb3JkZXJlZA0KYGBgDQpObyBnZWFyIGRldGFpbHMgaW4gY29sbGVjdGlvbmNvZGUuIFRoZSBNZXRhZGF0YSBvbiBPQklTIGFsc28gZ2l2ZXMgbm8gZGV0YWlscy4gZ2VhciA9IE5BIA0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJBdGxhbnRpYyBSZWZlcmVuY2UgQ2VudHJlIE11c2V1bSBvZiBDYW5hZGlhbiBBdGxhbnRpYyBPcmdhbmlzbXMgLSBJbnZlcnRlYnJhdGVzIGFuZCBGaXNoZXMgRGF0YSJdIDwtICJOQSINCmBgYA0KDQpbQXRsYW50aWMgWm9uZSBNb25pdG9yaW5nIFByb2dyYW0gTWFyaXRpbWVzIFJlZ2lvbiAoQVpNUCkgcGxhbmt0b24gZGF0YXNldHMuIEluOiBGaXNoZXJpZXMgYW5kIE9jZWFucyBDYW5hZGEgLSBCaW9DaGVtIGFyY2hpdmVdKGh0dHA6Ly9pb2Jpcy5vcmcvZXhwbG9yZS8jL2RhdGFzZXQvMjMyOCkuIA0KYGBge3J9DQphem1wbWFyIDwtIHN1YnNldChhZGRkYXRhLCByZXNuYW1lID09ICJBdGxhbnRpYyBab25lIE1vbml0b3JpbmcgUHJvZ3JhbSBNYXJpdGltZXMgUmVnaW9uIChBWk1QKSBwbGFua3RvbiBkYXRhc2V0cy4gSW46IEZpc2hlcmllcyBhbmQgT2NlYW5zIENhbmFkYSAtIEJpb0NoZW0gYXJjaGl2ZSIpDQphem1wbWFyJGNvbGxlY3Rpb25jb2RlIDwtIGFzLmNoYXJhY3Rlcihhem1wbWFyJGNvbGxlY3Rpb25jb2RlKQ0KYXptcG1hcl9jb2wgPC0gdW5pcXVlKGF6bXBtYXIkY29sbGVjdGlvbmNvZGUpICNtYWtlcyBhIHZhcmlhYmxlIG9mIGluc3RpdHV0aW9ucw0KYXptcG1hcl9jb2xvcmRlcmVkIDwtIHNvcnQoYXptcG1hcl9jb2wpICNqdXN0IHB1dHMgdGhlIGxpc3QgaW4gDQphem1wbWFyX2NvbG9yZGVyZWQNCmBgYA0KTm8gZ2VhciBkZXRhaWxzIGluIGNvbGxlY3Rpb25jb2RlLiBUaGUgbWV0YWRhdGEgb24gT0JJUyBpbmRpY2F0ZXMgdmVydGljYWwgcGxhbmt0b24gdG93IA0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJBdGxhbnRpYyBab25lIE1vbml0b3JpbmcgUHJvZ3JhbSBNYXJpdGltZXMgUmVnaW9uIChBWk1QKSBwbGFua3RvbiBkYXRhc2V0cy4gSW46IEZpc2hlcmllcyBhbmQgT2NlYW5zIENhbmFkYSAtIEJpb0NoZW0gYXJjaGl2ZSJdIDwtICJ2ZXJ0aWNhbF9wbGFua3Rvbl90b3ciDQpgYGANCg0KW0Jpb0NoZW0gem9vcGxhbmt0b24gc2FtcGxlcyBmcm9tIHRoZSBHdWxseSwgMjAwNi0yMDA3XShodHRwOi8vaW9iaXMub3JnL2V4cGxvcmUvIy9kYXRhc2V0LzIzMjcpLiANCmBgYHtyfQ0KYmlvZ3VsIDwtIHN1YnNldChhZGRkYXRhLCByZXNuYW1lID09ICJCaW9DaGVtIHpvb3BsYW5rdG9uIHNhbXBsZXMgZnJvbSB0aGUgR3VsbHksIDIwMDYtMjAwNyIpDQpiaW9ndWwkY29sbGVjdGlvbmNvZGUgPC0gYXMuY2hhcmFjdGVyKGJpb2d1bCRjb2xsZWN0aW9uY29kZSkNCmJpb2d1bF9jb2wgPC0gdW5pcXVlKGJpb2d1bCRjb2xsZWN0aW9uY29kZSkgI21ha2VzIGEgdmFyaWFibGUgb2YgaW5zdGl0dXRpb25zDQpiaW9ndWxfY29sb3JkZXJlZCA8LSBzb3J0KGJpb2d1bF9jb2wpICNqdXN0IHB1dHMgdGhlIGxpc3QgaW4gDQpiaW9ndWxfY29sb3JkZXJlZA0KYGBgDQpBbG9uZyB3aXRoIHRoZSBPQklTIG1ldGFkYXRhLCBpbmRpY2F0ZXMgZ2VhciA9IHZlcnRpY2FsIHBsYW5rdG9uIHRvdw0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJCaW9DaGVtIHpvb3BsYW5rdG9uIHNhbXBsZXMgZnJvbSB0aGUgR3VsbHksIDIwMDYtMjAwNyJdIDwtICJ2ZXJ0aWNhbF9wbGFua3Rvbl90b3ciDQpgYGANCg0KW0Jpb0NoZW06IERGTyBBdGxhbnRpYyBab25lIE1vbml0b3JpbmcgUHJvZ3JhbSBwbGFua3RvbiBkYXRhc2V0cyAtIE5ld2ZvdW5kbGFuZCBhbmQgTGFicmFkb3IgUmVnaW9uIChPQklTIENhbmFkYSldKGh0dHA6Ly9pb2Jpcy5vcmcvZXhwbG9yZS8jL2RhdGFzZXQvMjY2NikuIA0KYGBge3J9DQphem1wbmwgPC0gc3Vic2V0KGFkZGRhdGEsIHJlc25hbWUgPT0gIkJpb0NoZW06IERGTyBBdGxhbnRpYyBab25lIE1vbml0b3JpbmcgUHJvZ3JhbSBwbGFua3RvbiBkYXRhc2V0cyAtIE5ld2ZvdW5kbGFuZCBhbmQgTGFicmFkb3IgUmVnaW9uIChPQklTIENhbmFkYSIpDQphem1wbmwkY29sbGVjdGlvbmNvZGUgPC0gYXMuY2hhcmFjdGVyKGF6bXBubCRjb2xsZWN0aW9uY29kZSkNCmF6bXBubF9jb2wgPC0gdW5pcXVlKGF6bXBubCRjb2xsZWN0aW9uY29kZSkgI21ha2VzIGEgdmFyaWFibGUgb2YgaW5zdGl0dXRpb25zDQphem1wbmxfY29sb3JkZXJlZCA8LSBzb3J0KGF6bXBubF9jb2wpICNqdXN0IHB1dHMgdGhlIGxpc3QgaW4gDQphem1wbmxfY29sb3JkZXJlZA0KYGBgDQpObyBkZXRhaWxzIGluIGNvbGxlY3Rpb25jb2RlLiBPYmlzIG1ldGFkYXRhIGluZGljYXRlcyBnZWFyID0gdmVydGljYWwgcGxhbmt0b24gdG93DQpgYGB7cn0NCmFkZGRhdGEkZ2VhclthZGRkYXRhJHJlc25hbWUgPT0gIkJpb0NoZW06IERGTyBBdGxhbnRpYyBab25lIE1vbml0b3JpbmcgUHJvZ3JhbSBwbGFua3RvbiBkYXRhc2V0cyAtIE5ld2ZvdW5kbGFuZCBhbmQgTGFicmFkb3IgUmVnaW9uIChPQklTIENhbmFkYSkiXSA8LSAidmVydGljYWxfcGxhbmt0b25fdG93Ig0KYGBgDQoNCltCaW9DaGVtOiBTYW1lb3RvIHpvb3BsYW5rdG9uIGNvbGxlY3Rpb25dKGh0dHA6Ly9pb2Jpcy5vcmcvZXhwbG9yZS8jL2RhdGFzZXQvMjY3MCkuVmVydGljYWwgcGxhbmt0b24gdG93DQpgYGB7cn0NCmJpb3NhbSA8LSBzdWJzZXQoYWRkZGF0YSwgcmVzbmFtZSA9PSAiQmlvQ2hlbTogU2FtZW90byB6b29wbGFua3RvbiBjb2xsZWN0aW9uIikNCmJpb3NhbSRjb2xsZWN0aW9uY29kZSA8LSBhcy5jaGFyYWN0ZXIoYmlvc2FtJGNvbGxlY3Rpb25jb2RlKQ0KYmlvc2FtX2NvbCA8LSB1bmlxdWUoYmlvc2FtJGNvbGxlY3Rpb25jb2RlKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCmJpb3NhbV9jb2xvcmRlcmVkIDwtIHNvcnQoYmlvc2FtX2NvbCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCmJpb3NhbV9jb2xvcmRlcmVkDQpgYGANCkluc3VmZmljaWVudCBkZXRhaWxzIGluIGNvbGxlY3Rpb25jb2RlLiBPYmlzIG1ldGFkYXRhIGluZGljYXRlcyBnZWFyID0gdmVydGljYWwgcGxhbmt0b24gdG93DQpgYGB7cn0NCmFkZGRhdGEkZ2VhclthZGRkYXRhJHJlc25hbWUgPT0gIkJpb0NoZW06IFNhbWVvdG8gem9vcGxhbmt0b24gY29sbGVjdGlvbiJdIDwtICJ2ZXJ0aWNhbF9wbGFua3Rvbl90b3ciDQpgYGANCg0KW0RGTyBDZW50cmFsIGFuZCBBcmN0aWMgTXVsdGktc3BlY2llcyBTdG9jayBBc3Nlc3NtZW50IFN1cnZleXNdKGh0dHA6Ly9pb2Jpcy5vcmcvZXhwbG9yZS8jL2RhdGFzZXQvMjI5MykuIEENCmBgYHtyfQ0KZGZvY2FzIDwtIHN1YnNldChhZGRkYXRhLCByZXNuYW1lID09ICJERk8gQ2VudHJhbCBhbmQgQXJjdGljIE11bHRpLXNwZWNpZXMgU3RvY2sgQXNzZXNzbWVudCBTdXJ2ZXlzIikNCmRmb2NhcyRjb2xsZWN0aW9uY29kZSA8LSBhcy5jaGFyYWN0ZXIoZGZvY2FzJGNvbGxlY3Rpb25jb2RlKQ0KZGZvY2FzX2NvbCA8LSB1bmlxdWUoZGZvY2FzJGNvbGxlY3Rpb25jb2RlKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCmRmb2Nhc19jb2xvcmRlcmVkIDwtIHNvcnQoZGZvY2FzX2NvbCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCmRmb2Nhc19jb2xvcmRlcmVkDQpgYGANCm9rIHRoZXNlIGFyZSBhbGwgdHlwZXMgb2YgYm90dG9tIHRyYXdsLg0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJERk8gQ2VudHJhbCBhbmQgQXJjdGljIE11bHRpLXNwZWNpZXMgU3RvY2sgQXNzZXNzbWVudCBTdXJ2ZXlzIiAmIGFkZGRhdGEkY29sbGVjdGlvbmNvZGUgPT0gIkRGT1N1cnZleV9Nb2RpZmllZCBBbGZyZWRvLTAzIl0gPC0gImJvdHRvbV90cmF3bF9hbGZyZWRvXzAzIg0KYWRkZGF0YSRnZWFyW2FkZGRhdGEkcmVzbmFtZSA9PSAiREZPIENlbnRyYWwgYW5kIEFyY3RpYyBNdWx0aS1zcGVjaWVzIFN0b2NrIEFzc2Vzc21lbnQgU3VydmV5cyIgJiBhZGRkYXRhJGNvbGxlY3Rpb25jb2RlID09ICJERk9TdXJ2ZXlfTW9kaWZpZWQgQ29zbW9zIDI2MDAiXSA8LSAiYm90dG9tX3RyYXdsX2Nvc21vc18yNjAwIg0KYWRkZGF0YSRnZWFyW2FkZGRhdGEkcmVzbmFtZSA9PSAiREZPIENlbnRyYWwgYW5kIEFyY3RpYyBNdWx0aS1zcGVjaWVzIFN0b2NrIEFzc2Vzc21lbnQgU3VydmV5cyIgJiBhZGRkYXRhJGNvbGxlY3Rpb25jb2RlID09ICJERk9TdXJ2ZXlfTW9kaWZpZWQgTW9kaWZpZWQgKDIxXCIpIENhbXBlbGVuIl0gPC0gImJvdHRvbV90cmF3bF9jYW1wZWxlbl8yMSINCmFkZGRhdGEkZ2VhclthZGRkYXRhJHJlc25hbWUgPT0gIkRGTyBDZW50cmFsIGFuZCBBcmN0aWMgTXVsdGktc3BlY2llcyBTdG9jayBBc3Nlc3NtZW50IFN1cnZleXMiICYgYWRkZGF0YSRjb2xsZWN0aW9uY29kZSA9PSAiREZPU3VydmV5X01vZGlmaWVkIFN0YW5kYXJkICgxNFwiKSBDYW1wZWxlbiJdIDwtICJib3R0b21fdHJhd2xfY2FtcGVsZW5fMTQiDQpgYGANCg0KW0RGTyBHdWxmIFJlZ2lvbiBHcm91bmRmaXNoIFJlc2VhcmNoIFZlc3NlbCBTdXJ2ZXlzXShib3R0b20gdHJhd2wpLiAgDQpgYGB7cn0NCmRmb2d1bGZhcyA8LSBzdWJzZXQoYWRkZGF0YSwgcmVzbmFtZSA9PSAiREZPIEd1bGYgUmVnaW9uIEdyb3VuZGZpc2ggUmVzZWFyY2ggVmVzc2VsIFN1cnZleXMiKQ0KZGZvZ3VsZmFzJGNvbGxlY3Rpb25jb2RlIDwtIGFzLmNoYXJhY3RlcihkZm9ndWxmYXMkY29sbGVjdGlvbmNvZGUpDQpkZm9ndWxmYXNfY29sIDwtIHVuaXF1ZShkZm9ndWxmYXMkY29sbGVjdGlvbmNvZGUpICNtYWtlcyBhIHZhcmlhYmxlIG9mIGluc3RpdHV0aW9ucw0KZGZvZ3VsZmFzX2NvbG9yZGVyZWQgPC0gc29ydChkZm9ndWxmYXNfY29sKSAjanVzdCBwdXRzIHRoZSBsaXN0IGluIA0KZGZvZ3VsZmFzX2NvbG9yZGVyZWQNCmBgYA0Kbm8gZ2VhciBkZXRhaWxzIGluIGNvbGxlY3Rpb24gY29kZS4gT0JJUyBtZXRhZGF0YSBpbmRpY2F0ZXMgVGhyZWUgc3VydmV5IHZlc3NlbHMgYW5kIHR3byB0eXBlcyBvZiBib3R0b20tdHJhd2xzIHdlcmUgdXNlZCBwcmlvciB0byAyMDAzOiB0aGUgRS4gRS4gUHJpbmNlIGZyb20gMTk3MS0xOTg1IHVzaW5nIGEgWWFua2VlIDM2IHRyYXdsLCB0aGUgTGFkeSBIYW1tb25kIGZyb20gMTk4NS0xOTkxIGFuZCB0aGUgQWxmcmVkIE5lZWRsZXIgZnJvbSAxOTkyLTIwMDIsIGJvdGggdXNpbmcgYSBXZXN0ZXJuIElJQSB0cmF3bC4gRHVlIHRvIGEgZmlyZSBvbiB0aGUgTmVlZGxlciwgdGhlIDIwMDMgc3VydmV5IHdhcyBjb25kdWN0ZWQgYnkgaXRzIHNpc3Rlci1zaGlwLCB0aGUgVGVtcGxlbWFuIHVzaW5nIHRoZSBXZXN0ZXJuIElJQSB0cmF3bC4gVGhpcyBzdXJ2ZXkgc3RhcnRlZCBsYXRlIGFuZCB3YXMgaW5jb21wbGV0ZS4gVGhlIHN1cnZleSB3YXMgY29uZHVjdGVkIGJ5IGJvdGggdGhlIE5lZWRsZXIgYW5kIHRoZSBUZWxlb3N0IGluIDIwMDQgYW5kIDIwMDUgYW5kIGJ5IHRoZSBUZWxlb3N0IHNpbmNlIHRoZW4sIHVzaW5nIHRoZSBXZXN0ZXJuIElJQSB0cmF3bC4gDQpOb3RlIHlvdSBoYXZlIG5vdCBjYXB0dXJlZCBzaGlwIGluZm9ybWF0aW9uIGFib3ZlIHNvIGxlYXZlIGl0IG91dCBoZXJlLiBZb3VyIGRhdGEgaXMgMTk5OCBvbndhcmRzIHRvIHRoZSBnZWFyIGZvciBhbGwgPSBib3R0b21fdHJhd2xfd2VzdGVybl9JSUENCmBgYHtyfQ0KYWRkZGF0YSRnZWFyW2FkZGRhdGEkcmVzbmFtZSA9PSAiREZPIEd1bGYgUmVnaW9uIEdyb3VuZGZpc2ggUmVzZWFyY2ggVmVzc2VsIFN1cnZleXMiXSA8LSAiYm90dG9tX3RyYXdsX3dlc3Rlcm5fSUlBIg0KYGBgDQoNCltERk8gTWFyaXRpbWVzIFJlc2VhcmNoIFZlc3NlbCBUcmF3bCBTdXJ2ZXlzIEZpc2ggT2JzZXJ2YXRpb25zXShodHRwOi8vaW9iaXMub3JnL2V4cGxvcmUvIy9kYXRhc2V0LzIzNykuDQpgYGB7cn0NCmRmb21hcyA8LSBzdWJzZXQoYWRkZGF0YSwgcmVzbmFtZSA9PSAiREZPIE1hcml0aW1lcyBSZXNlYXJjaCBWZXNzZWwgVHJhd2wgU3VydmV5cyBGaXNoIE9ic2VydmF0aW9ucyIpDQpkZm9tYXMkY29sbGVjdGlvbmNvZGUgPC0gYXMuY2hhcmFjdGVyKGRmb21hcyRjb2xsZWN0aW9uY29kZSkNCmRmb21hc19jb2wgPC0gdW5pcXVlKGRmb21hcyRjb2xsZWN0aW9uY29kZSkgI21ha2VzIGEgdmFyaWFibGUgb2YgaW5zdGl0dXRpb25zDQpkZm9tYXNfY29sb3JkZXJlZCA8LSBzb3J0KGRmb21hc19jb2wpICNqdXN0IHB1dHMgdGhlIGxpc3QgaW4gDQpkZm9tYXNfY29sb3JkZXJlZA0KYGBgDQppbnN1ZmZpZW50IGluZm9ybWF0aW9uLiBPQklTIG1ldGFkYXRhIGp1c3QgaW5kaWNhdGVzICJhIHZhcmlldHkgb2YgdHJhd2wgZ2VhciIuIGdlYXIgPSAiYm90dG9tX3RyYXdsIg0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJERk8gTWFyaXRpbWVzIFJlc2VhcmNoIFZlc3NlbCBUcmF3bCBTdXJ2ZXlzIEZpc2ggT2JzZXJ2YXRpb25zIl0gPC0gImJvdHRvbV90cmF3bCINCmBgYA0KDQpbREZPIE5ld2ZvdW5kbGFuZCBhbmQgTGFicmFkb3IgUmVnaW9uIEVjb3N5c3RlbSBUcmF3bCBTdXJ2ZXlzXShodHRwOi8vaW9iaXMub3JnL2V4cGxvcmUvIy9kYXRhc2V0LzI4MTQpDQpgYGB7cn0NCmRmb25hcyA8LSBzdWJzZXQoYWRkZGF0YSwgcmVzbmFtZSA9PSAiREZPIE5ld2ZvdW5kbGFuZCBhbmQgTGFicmFkb3IgUmVnaW9uIEVjb3N5c3RlbSBUcmF3bCBTdXJ2ZXlzIikNCmRmb25hcyRjb2xsZWN0aW9uY29kZSA8LSBhcy5jaGFyYWN0ZXIoZGZvbmFzJGNvbGxlY3Rpb25jb2RlKQ0KZGZvbmFzX2NvbCA8LSB1bmlxdWUoZGZvbmFzJGNvbGxlY3Rpb25jb2RlKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCmRmb25hc19jb2xvcmRlcmVkIDwtIHNvcnQoZGZvbmFzX2NvbCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCmRmb25hc19jb2xvcmRlcmVkDQpgYGANCk1vcmUgdXNlZnVsLCBPQklTIG1ldGFkYXRhIGluZGljYXRlcyAiU3RhcnRpbmcgaW4gdGhlIGZhbGwgb2YgMTk5NSBzdXJ2ZXlzIGhhdmUgYmVlbiBjb25kdWN0ZWQgdXNpbmcgYSBDYW1wZWxlbiAxODAwIHRyYXdsIGZpdHRlZCB3aXRoIHJvY2staG9wcGVyIGZvb3QgZ2Vhci4iIGdlYXIgPSBib3R0b21fdHJhd2xfY2FtcGVsZW5fMTgwMA0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJERk8gTmV3Zm91bmRsYW5kIGFuZCBMYWJyYWRvciBSZWdpb24gRWNvc3lzdGVtIFRyYXdsIFN1cnZleXMiXSA8LSAiYm90dG9tX3RyYXdsX2NhbXBlbGVuXzE4MDAiDQpgYGANCg0KW0RGTyBRdWViZWMgUmVnaW9uIE11bHRpc3BlY2llcyBib3R0b20gdHJhd2wgc3VydmV5c10oaHR0cDovL2lvYmlzLm9yZy9leHBsb3JlLyMvZGF0YXNldC8yNTQyKQ0KYGBge3J9DQpkZm9xYXMgPC0gc3Vic2V0KGFkZGRhdGEsIHJlc25hbWUgPT0gIkRGTyBRdWViZWMgUmVnaW9uIE11bHRpc3BlY2llcyBib3R0b20gdHJhd2wgc3VydmV5cyIpDQpkZm9xYXMkY29sbGVjdGlvbmNvZGUgPC0gYXMuY2hhcmFjdGVyKGRmb3FhcyRjb2xsZWN0aW9uY29kZSkNCmRmb3Fhc19jb2wgPC0gdW5pcXVlKGRmb3FhcyRjb2xsZWN0aW9uY29kZSkgI21ha2VzIGEgdmFyaWFibGUgb2YgaW5zdGl0dXRpb25zDQpkZm9xYXNfY29sb3JkZXJlZCA8LSBzb3J0KGRmb3Fhc19jb2wpICNqdXN0IHB1dHMgdGhlIGxpc3QgaW4gDQpkZm9xYXNfY29sb3JkZXJlZA0KYGBgDQpubyBnZWFyIGRldGFpbHMgaW4gY29sbGVjdGlvbmNvZGUuIE9CSVMgbWV0YWRhdGEgaW5kaWNhdGVzIENhbXBlbGVuIDE4MDAuIGdlYXIgPSBib3R0b21fdHJhd2xfY2FtcGVsZW5fMTgwMA0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJERk8gUXVlYmVjIFJlZ2lvbiBNdWx0aXNwZWNpZXMgYm90dG9tIHRyYXdsIHN1cnZleXMiXSA8LSAiYm90dG9tX3RyYXdsX2NhbXBlbGVuXzE4MDAiDQpgYGANCg0KW0Zpc2ggc3BlY2ltZW5zXShodHRwOi8vaW9iaXMub3JnL2V4cGxvcmUvIy9kYXRhc2V0LzI0MTcpDQpgYGB7cn0NCmZpc2hzcCA8LSBzdWJzZXQoYWRkZGF0YSwgcmVzbmFtZSA9PSAiRmlzaCBzcGVjaW1lbnMiKQ0KZmlzaHNwJGNvbGxlY3Rpb25jb2RlIDwtIGFzLmNoYXJhY3RlcihmaXNoc3AkY29sbGVjdGlvbmNvZGUpDQpmaXNoc3BfY29sIDwtIHVuaXF1ZShmaXNoc3AkY29sbGVjdGlvbmNvZGUpICNtYWtlcyBhIHZhcmlhYmxlIG9mIGluc3RpdHV0aW9ucw0KZmlzaHNwX2NvbG9yZGVyZWQgPC0gc29ydChmaXNoc3BfY29sKSAjanVzdCBwdXRzIHRoZSBsaXN0IGluIA0KZmlzaHNwX2NvbG9yZGVyZWQNCmBgYA0Kbm8gZ2VhciBkZXRhaWwgaW4gY29sbGVjdGlvbmNvZGUuIE9CSVMgbWV0YWRhdGEgaW5kaWNhdGVzIHRoZXNlIGFyZSBtdXNldW0gcmVjb3Jkcy4gZ2VhciA9IE5BDQpgYGB7cn0NCmFkZGRhdGEkZ2VhclthZGRkYXRhJHJlc25hbWUgPT0gIkZpc2ggc3BlY2ltZW5zIl0gPC0gIk5BIg0KYGBgDQoNCltJY2h0aHlvbG9neSBDb2xsZWN0aW9uIC0gUm95YWwgT250YXJpbyBNdXNldW1dKGh0dHA6Ly9pb2Jpcy5vcmcvZXhwbG9yZS8jL2RhdGFzZXQvMzUxMSkNCmBgYHtyfQ0KaWNjb2wgPC0gc3Vic2V0KGFkZGRhdGEsIHJlc25hbWUgPT0gIkljaHRoeW9sb2d5IENvbGxlY3Rpb24gLSBSb3lhbCBPbnRhcmlvIE11c2V1bSIpDQppY2NvbCRjb2xsZWN0aW9uY29kZSA8LSBhcy5jaGFyYWN0ZXIoaWNjb2wkY29sbGVjdGlvbmNvZGUpDQppY2NvbF9jb2wgPC0gdW5pcXVlKGljY29sJGNvbGxlY3Rpb25jb2RlKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCmljY29sX2NvbG9yZGVyZWQgPC0gc29ydChpY2NvbF9jb2wpICNqdXN0IHB1dHMgdGhlIGxpc3QgaW4gDQppY2NvbF9jb2xvcmRlcmVkDQpgYGANCm5vIGdlYXIgZGV0YWlscyBpbiBjb2xsZWN0aW9uY29kZS4gT0JJUyBtZXRhZGF0YSBpbmRpY2F0ZXMgbXVzZXVtIHJlY29yZHMuIGdlYXIgPSBOQQ0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJJY2h0aHlvbG9neSBDb2xsZWN0aW9uIC0gUm95YWwgT250YXJpbyBNdXNldW0iXSA8LSAiTkEiDQpgYGANCg0KW01haW5lIERlcGFydG1lbnQgb2YgTWFyaW5lIFJlc291cmNlcyBJbnNob3JlIFRyYXdsIFN1cnZleSAyMDAww6LigqzigJwyMDA5XShodHRwOi8vaW9iaXMub3JnL2V4cGxvcmUvIy9kYXRhc2V0LzE2OTMpDQpgYGB7cn0NCm1kbXIgPC0gc3Vic2V0KGFkZGRhdGEsIHJlc25hbWUgPT0gIk1haW5lIERlcGFydG1lbnQgb2YgTWFyaW5lIFJlc291cmNlcyBJbnNob3JlIFRyYXdsIFN1cnZleSAyMDAww6LigqzigJwyMDA5IikNCm1kbXIkY29sbGVjdGlvbmNvZGUgPC0gYXMuY2hhcmFjdGVyKG1kbXIkY29sbGVjdGlvbmNvZGUpDQptZG1yX2NvbCA8LSB1bmlxdWUobWRtciRjb2xsZWN0aW9uY29kZSkgI21ha2VzIGEgdmFyaWFibGUgb2YgaW5zdGl0dXRpb25zDQptZG1yX2NvbG9yZGVyZWQgPC0gc29ydChtZG1yX2NvbCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCm1kbXJfY29sb3JkZXJlZA0KYGBgDQpJbnN1ZmZpY2llbnQgaW5mb21hdGlvbiBpbiBjb2xsZWN0aW9uY29kZS4gT0JJUyBtZXRhZGF0YSBpbmRpY2F0ZXMgImEgbW9kaWZpZWQgdmVyc2lvbiBvZiB0aGUgc2hyaW1wIG5ldCB1c2VkIGluIE1haW5lIHdhdGVycy4gSXQgd2FzIGRlc2lnbmVkIGJ5IHRoZSB2ZXNzZWwgb3duZXIgYW5kIG5ldCBkZXNpZ25lciBKZWZmIEZsYWdnIHRvIGZpc2ggZm9yIGEgdmFyaWV0eSBvZiBuZWFyLWJvdHRvbSBkd2VsbGluZyBzcGVjaWVzIHdpdGhvdXQgdGFyZ2V0aW5nIGFueSBzcGVjaWZpYyBjb21wb25lbnQiIGdlYXItdHlwZSA9ICJib3R0b21fdHJhd2wiDQpgYGB7cn0NCmFkZGRhdGEkZ2VhclthZGRkYXRhJHJlc25hbWUgPT0gIk1haW5lIERlcGFydG1lbnQgb2YgTWFyaW5lIFJlc291cmNlcyBJbnNob3JlIFRyYXdsIFN1cnZleSAyMDAww6LigqzigJwyMDA5Il0gPC0gImJvdHRvbV90cmF3bCINCmBgYA0KDQpbTm9ydGhlYXN0IEZpc2hlcmllcyBTY2llbmNlIENlbnRlciBCb3R0b20gVHJhd2wgU3VydmV5IERhdGFdKGh0dHA6Ly9pb2Jpcy5vcmcvZXhwbG9yZS8jL2RhdGFzZXQvMTQzNSkNCmBgYHtyfQ0KbmVmc3UgPC0gc3Vic2V0KGFkZGRhdGEsIHJlc25hbWUgPT0gIk5vcnRoZWFzdCBGaXNoZXJpZXMgU2NpZW5jZSBDZW50ZXIgQm90dG9tIFRyYXdsIFN1cnZleSBEYXRhIikNCm5lZnN1JGNvbGxlY3Rpb25jb2RlIDwtIGFzLmNoYXJhY3RlcihuZWZzdSRjb2xsZWN0aW9uY29kZSkNCm5lZnN1X2NvbCA8LSB1bmlxdWUobmVmc3UkY29sbGVjdGlvbmNvZGUpICNtYWtlcyBhIHZhcmlhYmxlIG9mIGluc3RpdHV0aW9ucw0KbmVmc3VfY29sb3JkZXJlZCA8LSBzb3J0KG5lZnN1X2NvbCkgI2p1c3QgcHV0cyB0aGUgbGlzdCBpbiANCm5lZnN1X2NvbG9yZGVyZWQNCmBgYA0KaW5zdWZmaWNpZW50IGRldGFpbCBpbiBjb2xsZWN0aW9uIGNvZGUuIE9CSVMgbWV0YWRhdGEgaW5kaWNhdGVzICJib3R0b20gdHJhd2wgZ2VhciIuIGdlYXIgPSAiYm90dG9tX3RyYXdsIg0KYGBge3J9DQphZGRkYXRhJGdlYXJbYWRkZGF0YSRyZXNuYW1lID09ICJOb3J0aGVhc3QgRmlzaGVyaWVzIFNjaWVuY2UgQ2VudGVyIEJvdHRvbSBUcmF3bCBTdXJ2ZXkgRGF0YSJdIDwtICJib3R0b21fdHJhd2wiDQpgYGANCg0KW05vcnRoZXJuIEd1bGYgb2YgU3QuIExhd3JlbmNlIEZpc2hlc10oaHR0cDovL2lvYmlzLm9yZy9leHBsb3JlLyMvZGF0YXNldC8yNjcxKQ0KYGBge3J9DQpuZ3NsIDwtIHN1YnNldChhZGRkYXRhLCByZXNuYW1lID09ICJOb3J0aGVybiBHdWxmIG9mIFN0LiBMYXdyZW5jZSBGaXNoZXMiKQ0KbmdzbCRjb2xsZWN0aW9uY29kZSA8LSBhcy5jaGFyYWN0ZXIobmdzbCRjb2xsZWN0aW9uY29kZSkNCm5nc2xfY29sIDwtIHVuaXF1ZShuZ3NsJGNvbGxlY3Rpb25jb2RlKSAjbWFrZXMgYSB2YXJpYWJsZSBvZiBpbnN0aXR1dGlvbnMNCm5nc2xfY29sb3JkZXJlZCA8LSBzb3J0KG5nc2xfY29sKSAjanVzdCBwdXRzIHRoZSBsaXN0IGluIA0KbmdzbF9jb2xvcmRlcmVkDQpgYGANCm5vIGdlYXIgZGV0YWlscyBpbiBjb2xsZWN0aW9uY29kZS4gT0JJUyBtZXRhZGF0YSBpbmRpY2F0ZXMgIlNhbXBsaW5nIG1ldGhvZHMgdXNlZCByYW5nZWQgZnJvbSBmaXNoIHRyYXBzIGFuZCBzZWluZSBuZXRzIG9uIHRoZSBjb2FzdHMgdG8gb2Zmc2hvcmUgdHJhd2xpbmciLiBnZWFyID0gTkENCmBgYHtyfQ0KYWRkZGF0YSRnZWFyW2FkZGRhdGEkcmVzbmFtZSA9PSAiTm9ydGhlcm4gR3VsZiBvZiBTdC4gTGF3cmVuY2UgRmlzaGVzIl0gPC0gIk5BIg0KYGBgDQoNCm9rIGNoZWNrIHRvIHNlZSBpZiBhbGwgb2YgZ2VhciBpcyBkb25lIChpZSBpZiB0aGVyZSBhcmUgYW55IHggbGVmdCkNCmBgYHtyfQ0KZ2VhcmNoZWNrIDwtIHN1YnNldChhZGRkYXRhLCBnZWFyID09ICJ4IikNCmdlYXJjaGVjaw0KYGBgDQp5YXkgLSBhbGwgZG9uZS4NCg0KIyBzZWUgd2hvIHNhbXBsZWQgaW4gd2hpY2ggeWVhciBhbmQgbW9udGgNCg0KeWVhcg0KYGBge3J9DQppbnN0X2J5X3lyIDwtIHdpdGgoYWRkZGF0YSwgdGFibGUoeWVhciwgaW5zdGl0dXRpb25jb2RlKSkNCndyaXRlLmNzdihpbnN0X2J5X3lyLCBmaWxlID0gIi4uL291dHB1dC9iaW8vaW5zdGl0dXRpb25jb2RlX2J5X3lyLmNzdiIpDQpgYGANCg0KbW9udGgNCmBgYHtyfQ0KaW5zdF9ieV9tdCA8LSB3aXRoKGFkZGRhdGEsIHRhYmxlKG1vbnRoLCBpbnN0aXR1dGlvbmNvZGUpKQ0Kd3JpdGUuY3N2KGluc3RfYnlfbXQsIGZpbGUgPSAiLi4vb3V0cHV0L2Jpby9pbnN0aXR1dGlvbmNvZGVfYnlfbXRoLmNzdiIpDQpgYGANCg0KIyBjcmVhdGUgYSB1bmlxdWUgY2VsbCBJRA0KDQpBIHVuaXF1ZSBjZWxsIElEIGxheWVyIGhhcyBiZWVuIGNyZWF0ZWQgaW4gdGhlIGVudmlyb25tZW50YWxfZGF0YV9wcmVwZXJhdGlvbi5SbWQuIE5vdyB5b3Ugd2FudCB0byBleHRyYWN0IHRoZSB2YWx1ZSBvZiB0aGF0IGxheWVyIHRvIHRoZSAuY3N2IHlvdSBhcmUgY3JlYXRpbmcuLi4NCg0KTG9hZCB0aGUgZW52LiBkYXRhDQpgYGB7cn0NCmxpYnJhcnkocmFzdGVyKQ0KY2VsbF9sYXllciA8LSByYXN0ZXIoIi4uL291dHB1dC9lbnYvZ2xvX3VuaXF1ZV9jZWxsLnRpZiIpICN0aGlzIGlzIGxvYWRpbmcgdGhlIGNlbGwgbGF5ZXIgdGhhdCB3YXMgY3JlYXRlZCBhbmQgc2F2ZWQgYXMgYSB0aWYNCnBsb3QoY2VsbF9sYXllcikNCmBgYA0KYW5kIGp1c3QgZ3JhYiB0aGUgYXR0cmlidXRlcyBvZiB0aGUgY2VsbF9sYXllcg0KYGBge3J9DQpjZWxsX2xheWVyDQpgYGANCg0KDQpUaGUgb2NjdXJyZW5jZSBkYXRhIG5lZWRzIHRvIGJlIGNvbnZlcnRlZCBpbnRvIHNwYXRpYWxwb2ludHMgZGF0YWZyYW1lDQpgYGB7cn0NCmxpYnJhcnkoc3ApDQp4eSA8LSBhZGRkYXRhWyAsYygzLDIpXSAjMyA9IGRlY2ltYWxMb25naXR1ZGUsIDIgPSBkZWNpbWFsTGF0aXR1ZGUNCmFkZGRhdGFfYWVhIDwtIFNwYXRpYWxQb2ludHNEYXRhRnJhbWUoY29vcmRzID0geHksIGRhdGEgPSBhZGRkYXRhLCBwcm9qNHN0cmluZyA9IENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwIikpDQphZGRkYXRhX2FlYQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KYWRkZGF0YV9hZWEgPC0gc3BUcmFuc2Zvcm0oYWRkZGF0YV9hZWEsIENSUyA9ICIrcHJvaj1hZWEgK2xhdF8xPTUwICtsYXRfMj03MCArbGF0XzA9NDAgK2xvbl8wPS02MCAreF8wPTAgK3lfMD0wICtlbGxwcz1HUlM4MCArZGF0dW09TkFEODMgK3VuaXRzPW0gK25vX2RlZnMiKSAjbm90ZSAtNjAgdXNlZCB0byBiZSAtOTEuIENoYW5nZWQgdG8gJ3N0cmFpZ2h0ZW4gdXAnDQphZGRkYXRhX2FlYQ0KYGBgDQoNCmFuZCBwbG90IGFuZCBXcml0ZSB0aGUgdHJhbnNmb3JtZWQgc3BlY2llcyBkYXRhIHRvIGEgbmV3IGNzdiAodGhpcyB3aWxsIGFsc28gaGF2ZSB0aGUgY29vcmRpbmF0ZXMgaW4gbWV0ZXJzIC0gbm90ZSBtZXRlcnMgYXJlIHVuZGVyIGRlY2ltYWxMb25naXR1ZGUxIGFuZCBkZWNpbWFsTGF0aXR1ZGUxKS4uLg0KYGBge3J9DQpwbG90KGFkZGRhdGFfYWVhLCBheGVzPVRSVUUsIGNleC5heGlzPS45NSkNCndyaXRlLmNzdihhZGRkYXRhX2FlYSwgZmlsZSA9ICIuLi9vdXRwdXQvYmlvL2RhdGFfYWVhLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCk9rIG5vdyBwbG90IHRoZSBlbnYuIGFuZCBwb2ludCBkYXRhLi4uDQpgYGB7cn0NCnBsb3QoY2VsbF9sYXllcikNCnBvaW50cyhhZGRkYXRhX2FlYSRkZWNpbWFsTG9uZ2l0dWRlLCBhZGRkYXRhX2FlYSRkZWNpbWFsTGF0aXR1ZGUpDQpgYGANCg0Kb2sgbm93IHRoZSBuZXh0IHN0ZXAgaXMgdG8gZXh0cmFjdCB0aGUgdW5pcXVlIGNlbGwgdmFsdWUgYW5kIGFkZCB0byBlYWNoIG9mIHRoZSBwb2ludHMNCnRoZW4gd3JpdGUgYSAuY3N2DQp0aGVuIGNvbnZlcnQgYmFjayB0byBhIG5vcm1hbCBkYXRhZnJhbWUNCmBgYHtyfQ0KYWRkZGF0YV9hZWEkY2VsbF9pZCA8LSBleHRyYWN0KHg9Y2VsbF9sYXllciwgeSA9IGFkZGRhdGFfYWVhKQ0Kd3JpdGUuY3N2KGFkZGRhdGFfYWVhLCBmaWxlID0gIi4uL291dHB1dC9iaW8vZGF0YV9hZWFfY2VsbC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkNCmRhdGFfYWVhIDwtIGFzLmRhdGEuZnJhbWUoYWRkZGF0YV9hZWEpDQpoZWFkKGRhdGFfYWVhKQ0KYGBgDQpsb29raW5nIGF0IHRoZSBoZWFkZXIgZGF0YSwgdGhlcmUgc2VlbXMgdG8gYmUgc29tZSBuZXcgY29sdW1ucyBjcmVhdGVkIG9uIHRoZSB3YXkuLi4NCmBgYHtyfQ0KY29sbmFtZXMoZGF0YV9hZWEpDQpgYGANCkkgZG9uJ3Qgd2FudCAib3B0aW9uYWwiIC0gZ2V0IHJpZCBvZiBpdCENCmBgYHtyfQ0KZGF0YV9hZWEgPC0gc3Vic2V0KGRhdGFfYWVhLCBzZWxlY3QgPSAtYyhvcHRpb25hbCkpDQpjb2xuYW1lcyhkYXRhX2FlYSkNCndyaXRlLmNzdihhZGRkYXRhX2FlYSwgZmlsZSA9ICIuLi9vdXRwdXQvYmlvL2RhdGFfYWVhX2NlbGwuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KIyBBZGQgQU1PIERhdGENClRoZSBkYXRhIGhhcyBiZWVuIHByZXBhcmVkIGFzIHBlciB0aGUgZW52aXJvbm1lbnRhbF9kYXRhX3ByZXBlcmF0aW9uLlJtZA0KDQpgYGB7cn0NCmFtbyA8LSByZWFkLmNzdigiLi4vb3V0cHV0L2Vudi9hbW8uY3N2IiwgaGVhZGVyPVRSVUUpDQpoZWFkKGFtbykNCmBgYA0KDQpTbyB5b3Ugd2FudC4uDQotIEFNTyB2YWx1ZSBhdCBzYW1wbGluZyBtb250aC95ZWFyDQotIEFNTyB2YWx1ZSBhdCBwcmV2aW91cyBzYW1wbGluZyBtb250aC95ZWFyDQotIEFNTyBwaGFzZSBhdCBwcmV2aW91cyB3aW50ZXIgKGJlY2F1c2UgdGhlIHdpbnRlciB2YWx1ZXMgYXJlIHRob3VnaHQgdG8gYmUgYSBtYWpvciBkcml2ZXIgb2Ygb2NlYW4gY29uZGl0aW9ucyBpbiB0aGUgZm9sbG93aW5nIHNwcmluZywgc3VtbWVyLCBhbmQgYXV0dW1uKQ0KDQpjaGFuZ2UgbW9udGggY29sIG5hbWVzIHRvIG51bWVyaWMNCg0KYGBge3J9DQpuYW1lcyhhbW8pWzI6MTNdID0gYygiMSIsICIyIiwiMyIsICI0IiwgIjUiLCAiNiIsICI3IiwgIjgiLCAiOSIsICIxMCIsICIxMSIsICIxMiIpDQpoZWFkKGFtbykNCmBgYA0KDQoNClN0YXJ0IHdpdGggdGhlIG1vbnRoIGRhdGEgZmlyc3QuLi5zdWJzZXQgY29scyAxOjEzICh3aGVyZSB0aGUgeWVhciBhbmQgbW9udGggZGF0YSBhcmUgaGVsZCkNCmBgYHtyfQ0KYW1vX3lybXQgPC0gYW1vWyAsMToxM10NCmFtb195cm10DQpgYGANCg0KYGBge3J9DQphbW9feXJtdCA8LSByZXNoYXBlKGFtb195cm10LCANCiAgdmFyeWluZyA9IGMoIjEiLCAiMiIsIjMiLCAiNCIsICI1IiwgIjYiLCAiNyIsICI4IiwgIjkiLCAiMTAiLCAiMTEiLCAiMTIiKSwNCiAgdi5uYW1lcyA9ICJ2YWx1ZSIsDQogIGRpcmVjdGlvbiA9ICJsb25nIikNCg0KYW1vX3lybXQgPC0gYW1vX3lybXRbb3JkZXIoYW1vX3lybXQkeWVhciksXQ0KYW1vX3lybXQNCmBgYA0KcmVuYW1lIHRpbWUgdG8gbW9udGguLiBhbmQgdmFsdWUgdG8gYW1vX3NhbXBsZQ0KYGBge3J9DQpjb2xuYW1lcyhhbW9feXJtdClbMl0gPC0gIm1vbnRoIg0KY29sbmFtZXMoYW1vX3lybXQpWzNdIDwtICJhbW9fc2FtcGxlIg0KYW1vX3lybXQNCmBgYA0KDQpub3cgbWF0Y2ggdGhlIHllYXIgYW5kIHRoZSBtb250aCBpbiB0aGUgdHdvIGRhdGFmcmFtZXMsIGFuZCBwb3B1bGF0ZSB0aGUgc3BlY2llcyBkYXRhc2V0IChkYXRhX2FlYSkgd2l0aCBhbW9fc2FtcGxlDQpgYGB7cn0NCmRhdGFfYWVhIDwtIG1lcmdlKHggPSBkYXRhX2FlYSwgeSA9IGFtb195cm10WyAsIGMoInllYXIiLCAibW9udGgiLCAiYW1vX3NhbXBsZSIpXSwgYnkgPSBjKCJ5ZWFyIiwgIm1vbnRoIiksIGFsbC54ID0gVFJVRSkNCmRhdGFfYWVhDQpgYGANCg0Kb2sgbmV4dCAtIEFNTyB2YWx1ZSBhdCBwcmV2aW91cyBzYW1wbGluZyBtb250aC95ZWFyDQoNCnNoaWZ0IHRoZSBhbW9fc2FtcGxlIGNvbHVtbiBkb3duIGJ5IDEuLi4NCmBgYHtyfQ0KbGlicmFyeSh1c2VmdWwpDQphbW9feXJtdCA8LSBzaGlmdC5jb2x1bW4oZGF0YSA9IGFtb195cm10LCBjb2x1bW5zID0gImFtb19zYW1wbGUiLCB1cCA9IEZBTFNFKQ0KYW1vX3lybXQNCmBgYA0KDQpOb3RlIHRoZSBzaGlmdGVkIHZhbHVlcyBhcmUgaW4gYSBuZXcgY29sdW1uIGNhbGxlZCBhbW9fc2FtcGxlLlNoaWZ0ZWQuIHJlbmFtZSB0byBhbW9fcHJldg0KYGBge3J9DQpjb2xuYW1lcyhhbW9feXJtdClbY29sbmFtZXMoYW1vX3lybXQpPT0iYW1vX3NhbXBsZS5TaGlmdGVkIl0gPC0gImFtb19wcmV2Ig0KYW1vX3lybXQNCndyaXRlLmNzdihhbW9feXJtdCwgIi4uL291dHB1dC9lbnYvYW1vX3ByZXYuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpICNmb3Igc29tZSByZWFzb24gaSBuZWVkIHRvIHdyaXRlIHRvIGEgY3N2IGFuZCByZWxvYWQgZm9yIHRoZSBuZXh0IHN0ZXAgdG8gd29yayBwcm9wZXJseQ0KYGBgDQoNCm5vdyBncmFiIHRoZSBkYXRhLi4uDQpgYGB7cn0NCmFtb19wcmV2IDwtIHJlYWQuY3N2KCIuLi9vdXRwdXQvZW52L2Ftb19wcmV2LmNzdiIpDQpkYXRhX2FlYSA8LSBtZXJnZSh4ID0gZGF0YV9hZWEsIHkgPSBhbW9fcHJldlsgLCBjKCJ5ZWFyIiwgIm1vbnRoIiwgImFtb19wcmV2IildLCBieSA9IGMoInllYXIiLCAibW9udGgiKSwgYWxsLnggPSBUUlVFKQ0KZGF0YV9hZWENCmBgYA0KDQphbmQgbm93IC0gQU1PIHBoYXNlIGF0IHByZXZpb3VzIHdpbnRlciAoYmVjYXVzZSB0aGUgd2ludGVyIHZhbHVlcyBhcmUgdGhvdWdodCB0byBiZSBhIG1ham9yIGRyaXZlciBvZiBvY2VhbiBjb25kaXRpb25zIGluIHRoZSBmb2xsb3dpbmcgc3ByaW5nLCBzdW1tZXIsIGFuZCBhdXR1bW4pDQoNCnNhbWUgcHJvY2VzcyBhcyBiZWZvcmUgLSBzaGlmdCByb3cgdGhlbiBtYXRjaA0KDQpCdXQgZmlyc3QhDQoNCllvdSBuZWVkIHRvIGV4dHJhY3QgdGhlIHNlYXNvbmFsIHZhbHVlcyBmcm9tIHRoZSBhbW8gZGF0YXNldA0KYGBge3J9DQphbW9fd2ludGVyIDwtIHN1YnNldChhbW8sIHNlbGVjdCA9IGMoInllYXIiLCAiV2ludGVyQXZnIikpDQphbW9fd2ludGVyDQpgYGANCg0Kbm93IHNoaWZ0IHRoZSB3aW50ZXIgYXZlcmFnZSBkYXRhIA0KYGBge3J9DQphbW9fd2ludGVyIDwtIHNoaWZ0LmNvbHVtbihkYXRhID0gYW1vX3dpbnRlciwgY29sdW1ucyA9ICJXaW50ZXJBdmciLCB1cCA9IEZBTFNFKQ0KYW1vX3dpbnRlcg0Kd3JpdGUuY3N2KGFtb193aW50ZXIsICIuLi9vdXRwdXQvZW52L2Ftb193aW50ZXIuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpICNmb3Igc29tZSByZWFzb24gbmVlZCB0byBzYXZlIHRvIGNzdiB0aGVuIHJlbG9hZCBpbiB0aGUgbmV4dCBzdGVwLi4uDQpgYGANCnJlbWVtYmVyIHlvdXIgc2hpZnRlZCBjb2x1bW4gaXMgY2FsbGVkIFdpbnRlckF2Zy5TaGlmdGVkDQoNCm5vdyBleHRyYWN0IHRoZSBXaW50ZXJBdmcuU2hpZnRlZCB2YWx1ZXMgdG8gdGhlIHNwZWNpZXMgZGF0YXNldA0KYGBge3J9DQphbW9fd2ludGVyIDwtIHJlYWQuY3N2KCIuLi9vdXRwdXQvZW52L2Ftb193aW50ZXIuY3N2IikNCmRhdGFfYWVhIDwtIG1lcmdlKHggPSBkYXRhX2FlYSwgeSA9IGFtb193aW50ZXJbICwgYygieWVhciIsICJXaW50ZXJBdmcuU2hpZnRlZCIpXSwgYnkgPSBjKCJ5ZWFyIiksIGFsbC54ID0gVFJVRSkNCmNvbG5hbWVzKGRhdGFfYWVhKVtjb2xuYW1lcyhkYXRhX2FlYSk9PSJXaW50ZXJBdmcuU2hpZnRlZCJdIDwtICJhbW9fd2ludGVyIiAjY2hhbmdlIHRoZSBjb2xuYW1lDQpkYXRhX2FlYQ0KYGBgDQpvayBhbmQgd3JpdGUgYSBjc3YNCmBgYHtyfQ0Kd3JpdGUuY3N2KGRhdGFfYWVhLCIuLi9vdXRwdXQvYmlvL2RhdGFfYWVhX2NlbGxfYW1vLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiNOQU8gdmFsdWVzDQoNClRoZSBkYXRhIGhhcyBiZWVuIHByZXBhcmVkIGFzIHBlciB0aGUgZW52aXJvbm1lbnRhbF9kYXRhX3ByZXBlcmF0aW9uLlJtZA0KDQpgYGB7cn0NCm5hbyA8LSByZWFkLmNzdigiLi4vb3V0cHV0L2Vudi9uYW8uY3N2IiwgaGVhZGVyPVRSVUUpDQpoZWFkKG5hbykNCmBgYA0KDQpTbyB5b3Ugd2FudC4uDQotIEFNTyB2YWx1ZSBhdCBzYW1wbGluZyBtb250aC95ZWFyDQotIEFNTyB2YWx1ZSBhdCBwcmV2aW91cyBzYW1wbGluZyBtb250aC95ZWFyDQotIEFNTyBwaGFzZSBhdCBwcmV2aW91cyB3aW50ZXIgKGJlY2F1c2UgdGhlIHdpbnRlciB2YWx1ZXMgYXJlIHRob3VnaHQgdG8gYmUgYSBtYWpvciBkcml2ZXIgb2Ygb2NlYW4gY29uZGl0aW9ucyBpbiB0aGUgZm9sbG93aW5nIHNwcmluZywgc3VtbWVyLCBhbmQgYXV0dW1uKQ0KDQpjaGFuZ2UgbW9udGggY29sIG5hbWVzIHRvIGp1c3QgbnVtZXJpYw0KYGBge3J9DQpuYW1lcyhuYW8pWzI6MTNdID0gYygiMSIsICIyIiwiMyIsICI0IiwgIjUiLCAiNiIsICI3IiwgIjgiLCAiOSIsICIxMCIsICIxMSIsICIxMiIpDQpoZWFkKG5hbykNCmBgYA0KDQpTdGFydCB3aXRoIHRoZSBtb250aCBkYXRhIGZpcnN0Li4uc3Vic2V0IGNvbHMgMToxMyAod2hlcmUgdGhlIHllYXIgYW5kIG1vbnRoIGRhdGEgYXJlIGhlbGQpDQoNCmBgYHtyfQ0KbmFvX3lybXQgPC0gbmFvWyAsMToxM10NCm5hb195cm10DQpgYGANCg0KYGBge3J9DQpuYW9feXJtdCA8LSByZXNoYXBlKG5hb195cm10LCANCiAgdmFyeWluZyA9IGMoIjEiLCAiMiIsIjMiLCAiNCIsICI1IiwgIjYiLCAiNyIsICI4IiwgIjkiLCAiMTAiLCAiMTEiLCAiMTIiKSwNCiAgdi5uYW1lcyA9ICJ2YWx1ZSIsDQogIGRpcmVjdGlvbiA9ICJsb25nIikNCg0KbmFvX3lybXQgPC0gbmFvX3lybXRbb3JkZXIoYW1vX3lybXQkeWVhciksXQ0KbmFvX3lybXQNCmBgYA0KDQpyZW5hbWUgdGltZSB0byBtb250aC4uIGFuZCB2YWx1ZSB0byBuYW9fc2FtcGxlDQoNCmBgYHtyfQ0KY29sbmFtZXMobmFvX3lybXQpWzJdIDwtICJtb250aCINCmNvbG5hbWVzKG5hb195cm10KVszXSA8LSAibmFvX3NhbXBsZSINCm5hb195cm10DQpgYGANCg0Kbm93IG1hdGNoIHRoZSB5ZWFyIGFuZCB0aGUgbW9udGggaW4gdGhlIHR3byBkYXRhZnJhbWVzLCBhbmQgcG9wdWxhdGUgdGhlIHNwZWNpZXMgZGF0YXNldCAoZGF0YV9hZWEpIHdpdGggbmFvX3NhbXBsZQ0KDQpgYGB7cn0NCmRhdGFfYWVhIDwtIG1lcmdlKHggPSBkYXRhX2FlYSwgeSA9IG5hb195cm10WyAsIGMoInllYXIiLCAibW9udGgiLCAibmFvX3NhbXBsZSIpXSwgYnkgPSBjKCJ5ZWFyIiwgIm1vbnRoIiksIGFsbC54ID0gVFJVRSkNCmRhdGFfYWVhDQpgYGANCg0Kb2sgbmV4dCAtIE5BTyB2YWx1ZSBhdCBwcmV2aW91cyBzYW1wbGluZyBtb250aC95ZWFyDQoNCnNoaWZ0IHRoZSBuYW9fc2FtcGxlIGNvbHVtbiBkb3duIGJ5IDEuLi4NCg0KYGBge3J9DQpsaWJyYXJ5KHVzZWZ1bCkNCm5hb195cm10IDwtIHNoaWZ0LmNvbHVtbihkYXRhID0gbmFvX3lybXQsIGNvbHVtbnMgPSAibmFvX3NhbXBsZSIsIHVwID0gRkFMU0UpDQpuYW9feXJtdA0KYGBgDQoNCk5vdGUgdGhlIHNoaWZ0ZWQgdmFsdWVzIGFyZSBpbiBhIG5ldyBjb2x1bW4gY2FsbGVkIGFtb19zYW1wbGUuU2hpZnRlZC4gcmVuYW1lIHRvIGFtb19wcmV2DQoNCmBgYHtyfQ0KY29sbmFtZXMobmFvX3lybXQpW2NvbG5hbWVzKG5hb195cm10KT09Im5hb19zYW1wbGUuU2hpZnRlZCJdIDwtICJuYW9fcHJldiINCm5hb195cm10DQp3cml0ZS5jc3YobmFvX3lybXQsICIuLi9vdXRwdXQvZW52L25hb19wcmV2LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKSAjZm9yIHNvbWUgcmVhc29uIGkgbmVlZCB0byB3cml0ZSB0byBhIGNzdiBhbmQgcmVsb2FkIGZvciB0aGUgbmV4dCBzdGVwIHRvIHdvcmsgcHJvcGVybHkNCmBgYA0KDQpub3cgZ3JhYiB0aGUgZGF0YS4uLg0KDQpgYGB7cn0NCm5hb19wcmV2IDwtIHJlYWQuY3N2KCIuLi9vdXRwdXQvZW52L25hb19wcmV2LmNzdiIpDQpkYXRhX2FlYSA8LSBtZXJnZSh4ID0gZGF0YV9hZWEsIHkgPSBuYW9fcHJldlsgLCBjKCJ5ZWFyIiwgIm1vbnRoIiwgIm5hb19wcmV2IildLCBieSA9IGMoInllYXIiLCAibW9udGgiKSwgYWxsLnggPSBUUlVFKQ0KZGF0YV9hZWENCmBgYA0KDQphbmQgbm93IC0gTkFPIHBoYXNlIGF0IHByZXZpb3VzIHdpbnRlciAoYmVjYXVzZSB0aGUgd2ludGVyIHZhbHVlcyBhcmUgdGhvdWdodCB0byBiZSBhIG1ham9yIGRyaXZlciBvZiBvY2VhbiBjb25kaXRpb25zIGluIHRoZSBmb2xsb3dpbmcgc3ByaW5nLCBzdW1tZXIsIGFuZCBhdXR1bW4pDQoNCnNhbWUgcHJvY2VzcyBhcyBiZWZvcmUgLSBzaGlmdCByb3cgdGhlbiBtYXRjaA0KDQpCdXQgZmlyc3QhDQoNCllvdSBuZWVkIHRvIGV4dHJhY3QgdGhlIHNlYXNvbmFsIHZhbHVlcyBmcm9tIHRoZSBOQU8gZGF0YXNldA0KDQpgYGB7cn0NCm5hb193aW50ZXIgPC0gc3Vic2V0KG5hbywgc2VsZWN0ID0gYygieWVhciIsICJXaW50ZXJBdmciKSkNCm5hb193aW50ZXINCmBgYA0KDQpub3cgc2hpZnQgdGhlIHdpbnRlciBhdmVyYWdlIGRhdGENCg0KYGBge3J9DQpuYW9fd2ludGVyIDwtIHNoaWZ0LmNvbHVtbihkYXRhID0gbmFvX3dpbnRlciwgY29sdW1ucyA9ICJXaW50ZXJBdmciLCB1cCA9IEZBTFNFKQ0KbmFvX3dpbnRlcg0Kd3JpdGUuY3N2KG5hb193aW50ZXIsICIuLi9vdXRwdXQvZW52L25hb193aW50ZXIuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpICNmb3Igc29tZSByZWFzb24gbmVlZCB0byBzYXZlIHRvIGNzdiB0aGVuIHJlbG9hZCBpbiB0aGUgbmV4dCBzdGVwLi4uDQoNCmBgYA0KDQpyZW1lbWJlciB5b3VyIHNoaWZ0ZWQgY29sdW1uIGlzIGNhbGxlZCBXaW50ZXJBdmcuU2hpZnRlZA0KDQpub3cgZXh0cmFjdCB0aGUgV2ludGVyQXZnLlNoaWZ0ZWQgdmFsdWVzIHRvIHRoZSBzcGVjaWVzIGRhdGFzZXQNCg0KYGBge3J9DQpuYW9fd2ludGVyIDwtIHJlYWQuY3N2KCIuLi9vdXRwdXQvZW52L25hb193aW50ZXIuY3N2IikNCmRhdGFfYWVhIDwtIG1lcmdlKHggPSBkYXRhX2FlYSwgeSA9IG5hb193aW50ZXJbICwgYygieWVhciIsICJXaW50ZXJBdmcuU2hpZnRlZCIpXSwgYnkgPSBjKCJ5ZWFyIiksIGFsbC54ID0gVFJVRSkNCmNvbG5hbWVzKGRhdGFfYWVhKVtjb2xuYW1lcyhkYXRhX2FlYSk9PSJXaW50ZXJBdmcuU2hpZnRlZCJdIDwtICJuYW9fd2ludGVyIiAjY2hhbmdlIHRoZSBjb2xuYW1lDQpkYXRhX2FlYQ0KYGBgDQoNCm9rIGFuZCB3cml0ZSBhIGNzdg0KDQpgYGB7cn0NCndyaXRlLmNzdihkYXRhX2FlYSwiLi4vb3V0cHV0L2Jpby9kYXRhX2FlYV9jZWxsX2Ftb19uYW8uY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KIyB3YXJtL2NvbGQgeWVhcg0KDQpUaGUgd2FybS9jb2xkIHllYXIgaW5kZXggd2lsbCBiZSB0YWtlbiBmcm9tIGEgW0RGTyBDU0FTIHJlcG9ydF0oaHR0cDovL3d3dy5kZm8tbXBvLmdjLmNhL2NzYXMtc2Njcy9QdWJsaWNhdGlvbnMvU0FSLUFTLzIwMTgvMjAxOF8wMzktZW5nLnBkZik=